aslan-h5/src/views/LoadingView.vue
2025-09-05 12:11:47 +08:00

459 lines
10 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="loading-view">
<!-- 背景渐变 -->
<div class="loading-background"></div>
<!-- 加载内容 -->
<div class="loading-content">
<!-- Logo或品牌标识 -->
<div class="logo-container">
<div class="logo">
<div class="logo-icon">📱</div>
<h1 class="logo-text">Likei</h1>
</div>
</div>
<!-- 加载动画 -->
<div class="loading-animation">
<div class="spinner">
<div class="spinner-ring"></div>
<div class="spinner-ring"></div>
<div class="spinner-ring"></div>
</div>
</div>
<!-- 加载文本 -->
<div class="loading-text">
<p class="main-text">{{ loadingText }}</p>
<p class="sub-text">{{ subText }}</p>
</div>
<!-- 进度条 -->
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill" :style="{ width: progress + '%' }"></div>
</div>
<span class="progress-text">{{ Math.round(progress) }}%</span>
</div>
</div>
<!-- 底部提示 -->
<div class="loading-footer">
<p>Powered by Likei Team</p>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { isInApp, connectApplication, parseAccessOrigin, parseHeader, setHttpHeaders } from '../utils/appBridge.js'
import { appConnectionManager } from '../utils/appConnectionManager.js'
import {getDefaultPage} from "@/utils/permissionManager.js";
const router = useRouter()
// 检查是否应该执行重定向
const checkShouldRedirect = () => {
const currentRoute = router.currentRoute.value
const currentPath = currentRoute.path
const routeName = currentRoute.name
console.log('Checking redirect conditions:', {
path: currentPath,
name: routeName,
url: window.location.href
})
// 只有当访问根路径或loading页面时才执行自动跳转
const isRootAccess = currentPath === '/' || routeName === 'root'
const isLoadingAccess = currentPath === '/loading' || routeName === 'loading'
console.log('Redirect decision:', {
isRootAccess,
isLoadingAccess,
shouldRedirect: isRootAccess || isLoadingAccess
})
return isRootAccess || isLoadingAccess
}
// 响应式数据
const loadingText = ref('Initializing...')
const subText = ref('Setting up your experience')
const progress = ref(0)
// 加载步骤配置
const loadingSteps = [
{ text: 'Connecting to server...', subText: 'Establishing secure connection', duration: 200 },
{ text: 'Loading user data...', subText: 'Retrieving your information', duration: 300 },
{ text: 'Setting up interface...', subText: 'Preparing your workspace', duration: 200 },
{ text: 'Almost ready...', subText: 'Finalizing setup', duration: 200 }
]
let currentStepIndex = 0
let progressInterval = null
let stepTimeout = null
// 开始加载流程
const startLoading = async () => {
try {
// 检查是否应该执行自动跳转
const shouldRedirect = checkShouldRedirect()
if (!shouldRedirect) {
console.log('User accessed specific path directly, not performing redirect')
return
}
// 如果在APP环境中进行连接
if (isInApp()) {
await connectToApp()
}
// 开始进度动画
startProgressAnimation()
// 等待加载完成
await waitForLoadingComplete()
// 跳转到目标页面
await navigateToTargetPage()
} catch (error) {
console.error('Loading failed:', error)
// 出错时跳转到错误页面
router.replace('/not_app')
}
}
// APP连接
const connectToApp = async () => {
return new Promise((resolve, reject) => {
connectApplication(async (access) => {
try {
const result = parseAccessOrigin(access)
if (result.success) {
const headerInfo = parseHeader(result.data)
await setHttpHeaders(headerInfo)
appConnectionManager.setConnected(headerInfo)
resolve()
} else {
reject(new Error(result.error))
}
} catch (error) {
reject(error)
}
})
})
}
// 开始进度动画
const startProgressAnimation = () => {
let currentProgress = 0
const totalDuration = loadingSteps.reduce((sum, step) => sum + step.duration, 0)
const progressIncrement = 100 / totalDuration * 50 // 每50ms增加的进度
progressInterval = setInterval(() => {
currentProgress += progressIncrement
progress.value = Math.min(currentProgress, 100)
if (progress.value >= 100) {
clearInterval(progressInterval)
}
}, 50)
// 更新步骤文本
updateLoadingStep()
}
// 更新加载步骤
const updateLoadingStep = () => {
if (currentStepIndex < loadingSteps.length) {
const step = loadingSteps[currentStepIndex]
loadingText.value = step.text
subText.value = step.subText
stepTimeout = setTimeout(() => {
currentStepIndex++
updateLoadingStep()
}, step.duration)
}
}
// 等待加载完成
const waitForLoadingComplete = () => {
return new Promise(resolve => {
const totalTime = loadingSteps.reduce((sum, step) => sum + step.duration, 0)
setTimeout(resolve, totalTime)
})
}
// 跳转到目标页面
const navigateToTargetPage = async () => {
try {
// 获取当前路由信息
const currentRoute = router.currentRoute.value
const currentPath = currentRoute.path
const routeName = currentRoute.name
console.log('Current path:', currentPath)
console.log('Route name:', routeName)
// 只有当访问根路径 ("/") 或者 loading 页面时,才跳转到默认页面
// 其他所有具体路径都不应该被重定向
if (currentPath === '/' || routeName === 'root' || currentPath === '/loading' || routeName === 'loading') {
console.log('Navigating to default page from root or loading')
router.replace(getDefaultPage())
} else {
console.log('User accessed specific path, not redirecting:', currentPath)
// 如果用户直接访问了具体路径,不进行任何跳转
return
}
} catch (error) {
console.error('Failed to get default page:', error)
// 出错时跳转到申请页面
router.replace('/apply')
}
}
// 清理定时器
const cleanup = () => {
if (progressInterval) {
clearInterval(progressInterval)
progressInterval = null
}
if (stepTimeout) {
clearTimeout(stepTimeout)
stepTimeout = null
}
}
// 生命周期
onMounted(() => {
startLoading()
})
onUnmounted(() => {
cleanup()
})
</script>
<style scoped>
.loading-view {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
overflow: hidden;
}
.loading-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.15) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.1) 0%, transparent 50%);
animation: backgroundShift 10s ease-in-out infinite;
}
@keyframes backgroundShift {
0%, 100% { transform: translateX(0) translateY(0); }
50% { transform: translateX(-10px) translateY(-5px); }
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
z-index: 2;
text-align: center;
max-width: 300px;
width: 100%;
padding: 0 20px;
}
.logo-container {
margin-bottom: 40px;
}
.logo {
display: flex;
flex-direction: column;
align-items: center;
animation: logoFloat 3s ease-in-out infinite;
}
@keyframes logoFloat {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.logo-icon {
font-size: 60px;
margin-bottom: 16px;
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}
.logo-text {
font-size: 32px;
font-weight: 700;
color: white;
margin: 0;
letter-spacing: 2px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.loading-animation {
margin-bottom: 30px;
}
.spinner {
position: relative;
width: 60px;
height: 60px;
}
.spinner-ring {
position: absolute;
width: 100%;
height: 100%;
border: 3px solid transparent;
border-top: 3px solid rgba(255, 255, 255, 0.8);
border-radius: 50%;
animation: spin 1.5s linear infinite;
}
.spinner-ring:nth-child(2) {
width: 80%;
height: 80%;
top: 10%;
left: 10%;
border-top-color: rgba(255, 255, 255, 0.6);
animation-duration: 2s;
animation-direction: reverse;
}
.spinner-ring:nth-child(3) {
width: 60%;
height: 60%;
top: 20%;
left: 20%;
border-top-color: rgba(255, 255, 255, 0.4);
animation-duration: 2.5s;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
margin-bottom: 30px;
color: white;
}
.main-text {
font-size: 18px;
font-weight: 600;
margin: 0 0 8px 0;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.sub-text {
font-size: 14px;
margin: 0;
opacity: 0.8;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.progress-container {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.progress-bar {
width: 100%;
height: 4px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 2px;
overflow: hidden;
backdrop-filter: blur(10px);
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #fff, rgba(255, 255, 255, 0.8));
border-radius: 2px;
transition: width 0.3s ease;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}
.progress-text {
font-size: 12px;
color: rgba(255, 255, 255, 0.9);
font-weight: 500;
}
.loading-footer {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 2;
}
.loading-footer p {
margin: 0;
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
text-align: center;
}
/* 响应式设计 */
@media (max-width: 480px) {
.loading-content {
max-width: 280px;
}
.logo-icon {
font-size: 50px;
}
.logo-text {
font-size: 28px;
}
.spinner {
width: 50px;
height: 50px;
}
.main-text {
font-size: 16px;
}
}
/* 暗黑模式支持 */
@media (prefers-color-scheme: dark) {
.loading-view {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
}
}
</style>