aslan-h5/src/views/LoadingView.vue
2025-08-22 18:07:39 +08:00

428 lines
9.3 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 { getTeamEntry } from '../api/wallet.js'
import { setUserInfo } from '../utils/userStore.js'
const router = useRouter()
// 响应式数据
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: 800 },
{ text: 'Loading user data...', subText: 'Retrieving your information', duration: 1000 },
{ text: 'Setting up interface...', subText: 'Preparing your workspace', duration: 600 },
{ text: 'Almost ready...', subText: 'Finalizing setup', duration: 400 }
]
let currentStepIndex = 0
let progressInterval = null
let stepTimeout = null
// 开始加载流程
const startLoading = async () => {
try {
// 如果在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 response = await getTeamEntry()
if (response && response.status && response.body) {
// 有团队信息,根据默认设置跳转到主页
const memberProfile = response.body.memberProfile
if (memberProfile) {
setUserInfo(memberProfile, response.body.teamProfile)
// 根据用户身份跳转到对应页面
// 这里可以根据需要调整默认跳转逻辑
router.replace('/host-center')
} else {
router.replace('/apply')
}
} else {
// 没有团队信息,跳转到申请页面
router.replace('/apply')
}
} catch (error) {
console.error('Failed to get team entry:', 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>