371 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
	<view class="splash-container">
 | 
						|
		<!-- 背景动画 -->
 | 
						|
		<view class="splash-background">
 | 
						|
			<view class="gradient-circle circle-1"></view>
 | 
						|
			<view class="gradient-circle circle-2"></view>
 | 
						|
			<view class="gradient-circle circle-3"></view>
 | 
						|
		</view>
 | 
						|
		
 | 
						|
		<!-- 主要内容 -->
 | 
						|
		<view class="splash-content">
 | 
						|
			<!-- Logo区域 -->
 | 
						|
			<view class="logo-section">
 | 
						|
				<view class="logo-container">
 | 
						|
					<text class="logo-text">{{appInfo.name}}</text>
 | 
						|
					<view class="logo-subtitle">{{appInfo.nameEn}}</view>
 | 
						|
				</view>
 | 
						|
				<view class="logo-icon">
 | 
						|
					<text class="icon-text">{{appInfo.logo}}</text>
 | 
						|
				</view>
 | 
						|
			</view>
 | 
						|
			
 | 
						|
			<!-- 加载动画 -->
 | 
						|
			<view class="loading-section">
 | 
						|
				<view class="loading-dots">
 | 
						|
					<view class="dot" :class="{ active: loadingStep >= 1 }"></view>
 | 
						|
					<view class="dot" :class="{ active: loadingStep >= 2 }"></view>
 | 
						|
					<view class="dot" :class="{ active: loadingStep >= 3 }"></view>
 | 
						|
				</view>
 | 
						|
				<text class="loading-text">{{loadingText}}</text>
 | 
						|
			</view>
 | 
						|
			
 | 
						|
			<!-- 版本信息 -->
 | 
						|
			<!-- <view class="version-info">
 | 
						|
				<text class="version-text">v{{appVersion}}</text>
 | 
						|
			</view> -->
 | 
						|
		</view>
 | 
						|
	</view>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
import { ref, onMounted } from 'vue'
 | 
						|
import { useAuthStore } from '../../src/store/authStore.js'
 | 
						|
import { 
 | 
						|
	initSplash, 
 | 
						|
	shouldShowSplash, 
 | 
						|
	markSplashShown, 
 | 
						|
	getSplashDuration,
 | 
						|
	loadingSteps,
 | 
						|
	executeLoadingStep,
 | 
						|
	onSplashComplete
 | 
						|
} from '../../src/utils/splashManager.js'
 | 
						|
import { getAppInfo, getLoadingSteps, getThemeConfig } from '../../src/config/splash.js'
 | 
						|
 | 
						|
export default {
 | 
						|
	name: 'SplashScreen',
 | 
						|
	setup() {
 | 
						|
		const authStore = useAuthStore()
 | 
						|
		const loadingStep = ref(0)
 | 
						|
		const loadingText = ref('正在初始化...')
 | 
						|
		const isLoading = ref(false)
 | 
						|
		
 | 
						|
		// 获取配置信息
 | 
						|
		const appInfo = getAppInfo()
 | 
						|
		const themeConfig = getThemeConfig()
 | 
						|
		const configLoadingSteps = getLoadingSteps()
 | 
						|
		
 | 
						|
		// 初始化启动画面
 | 
						|
		initSplash()
 | 
						|
		
 | 
						|
		// 启动加载动画
 | 
						|
		const startLoading = async () => {
 | 
						|
			if (isLoading.value) return
 | 
						|
			isLoading.value = true
 | 
						|
			
 | 
						|
			try {
 | 
						|
				// 执行每个加载步骤
 | 
						|
				for (let i = 0; i < configLoadingSteps.length; i++) {
 | 
						|
					const step = configLoadingSteps[i]
 | 
						|
					
 | 
						|
					// 更新UI
 | 
						|
					loadingStep.value = i + 1
 | 
						|
					loadingText.value = step.text
 | 
						|
					
 | 
						|
					// 执行步骤
 | 
						|
					const success = await executeLoadingStep(step)
 | 
						|
					
 | 
						|
					if (!success) {
 | 
						|
						console.warn(`步骤 ${step.action} 执行失败,继续下一步`)
 | 
						|
					}
 | 
						|
					
 | 
						|
					// 等待步骤完成时间
 | 
						|
					await new Promise(resolve => setTimeout(resolve, step.duration))
 | 
						|
				}
 | 
						|
				
 | 
						|
				// 确保最小显示时间
 | 
						|
				const minDuration = getSplashDuration()
 | 
						|
				if (minDuration > 0) {
 | 
						|
					await new Promise(resolve => setTimeout(resolve, minDuration))
 | 
						|
				}
 | 
						|
				
 | 
						|
				// 启动完成
 | 
						|
				onSplashComplete()
 | 
						|
				
 | 
						|
				// 根据登录状态跳转
 | 
						|
				if (authStore.isAuthenticated) {
 | 
						|
					// 已登录,跳转到主页面
 | 
						|
					uni.reLaunch({
 | 
						|
						url: '/pages/index/index'
 | 
						|
					})
 | 
						|
				} else {
 | 
						|
					// 未登录,跳转到登录页面
 | 
						|
					uni.reLaunch({
 | 
						|
						url: '/pages/login/index'
 | 
						|
					})
 | 
						|
				}
 | 
						|
				
 | 
						|
			} catch (error) {
 | 
						|
				console.error('启动过程出错:', error)
 | 
						|
				// 即使出错也要跳转,根据登录状态决定
 | 
						|
				if (authStore.isAuthenticated) {
 | 
						|
					uni.reLaunch({
 | 
						|
						url: '/pages/index/index'
 | 
						|
					})
 | 
						|
				} else {
 | 
						|
					uni.reLaunch({
 | 
						|
						url: '/pages/login/index'
 | 
						|
					})
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		onMounted(() => {
 | 
						|
			// 检查是否应该显示启动画面
 | 
						|
			if (shouldShowSplash()) {
 | 
						|
				// 延迟启动动画,让用户看到启动画面
 | 
						|
				setTimeout(() => {
 | 
						|
					startLoading()
 | 
						|
				}, 500)
 | 
						|
			} else {
 | 
						|
				// 直接跳转,根据登录状态决定
 | 
						|
				setTimeout(() => {
 | 
						|
					if (authStore.isAuthenticated) {
 | 
						|
						uni.reLaunch({
 | 
						|
							url: '/pages/index/index'
 | 
						|
						})
 | 
						|
					} else {
 | 
						|
						uni.reLaunch({
 | 
						|
							url: '/pages/login/index'
 | 
						|
						})
 | 
						|
					}
 | 
						|
				}, 100)
 | 
						|
			}
 | 
						|
		})
 | 
						|
		
 | 
						|
		return {
 | 
						|
			loadingStep,
 | 
						|
			loadingText,
 | 
						|
			appVersion: appInfo.version,
 | 
						|
			appInfo,
 | 
						|
			isLoading
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
</script>
 | 
						|
 | 
						|
<style lang="scss" scoped>
 | 
						|
.splash-container {
 | 
						|
	width: 100vw;
 | 
						|
	height: 100vh;
 | 
						|
	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 | 
						|
	position: relative;
 | 
						|
	overflow: hidden;
 | 
						|
	display: flex;
 | 
						|
	align-items: center;
 | 
						|
	justify-content: center;
 | 
						|
}
 | 
						|
 | 
						|
.splash-background {
 | 
						|
	position: absolute;
 | 
						|
	top: 0;
 | 
						|
	left: 0;
 | 
						|
	width: 100%;
 | 
						|
	height: 100%;
 | 
						|
	overflow: hidden;
 | 
						|
}
 | 
						|
 | 
						|
.gradient-circle {
 | 
						|
	position: absolute;
 | 
						|
	border-radius: 50%;
 | 
						|
	background: rgba(255, 255, 255, 0.1);
 | 
						|
	animation: float 6s ease-in-out infinite;
 | 
						|
}
 | 
						|
 | 
						|
.circle-1 {
 | 
						|
	width: 200rpx;
 | 
						|
	height: 200rpx;
 | 
						|
	top: 10%;
 | 
						|
	left: 10%;
 | 
						|
	animation-delay: 0s;
 | 
						|
}
 | 
						|
 | 
						|
.circle-2 {
 | 
						|
	width: 300rpx;
 | 
						|
	height: 300rpx;
 | 
						|
	top: 60%;
 | 
						|
	right: 10%;
 | 
						|
	animation-delay: 2s;
 | 
						|
}
 | 
						|
 | 
						|
.circle-3 {
 | 
						|
	width: 150rpx;
 | 
						|
	height: 150rpx;
 | 
						|
	top: 30%;
 | 
						|
	right: 30%;
 | 
						|
	animation-delay: 4s;
 | 
						|
}
 | 
						|
 | 
						|
@keyframes float {
 | 
						|
	0%, 100% {
 | 
						|
		transform: translateY(0px) rotate(0deg);
 | 
						|
		opacity: 0.7;
 | 
						|
	}
 | 
						|
	50% {
 | 
						|
		transform: translateY(-20px) rotate(180deg);
 | 
						|
		opacity: 0.3;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
.splash-content {
 | 
						|
	display: flex;
 | 
						|
	flex-direction: column;
 | 
						|
	align-items: center;
 | 
						|
	justify-content: center;
 | 
						|
	z-index: 10;
 | 
						|
	position: relative;
 | 
						|
}
 | 
						|
 | 
						|
.logo-section {
 | 
						|
	display: flex;
 | 
						|
	flex-direction: column;
 | 
						|
	align-items: center;
 | 
						|
	margin-bottom: 120rpx;
 | 
						|
	animation: fadeInUp 1s ease-out;
 | 
						|
}
 | 
						|
 | 
						|
.logo-container {
 | 
						|
	text-align: center;
 | 
						|
	margin-bottom: 40rpx;
 | 
						|
}
 | 
						|
 | 
						|
.logo-text {
 | 
						|
	font-size: 64rpx;
 | 
						|
	font-weight: 700;
 | 
						|
	color: #fff;
 | 
						|
	text-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.3);
 | 
						|
	display: block;
 | 
						|
	margin-bottom: 16rpx;
 | 
						|
}
 | 
						|
 | 
						|
.logo-subtitle {
 | 
						|
	font-size: 28rpx;
 | 
						|
	color: rgba(255, 255, 255, 0.8);
 | 
						|
	letter-spacing: 2rpx;
 | 
						|
}
 | 
						|
 | 
						|
.logo-icon {
 | 
						|
	width: 120rpx;
 | 
						|
	height: 120rpx;
 | 
						|
	background: rgba(255, 255, 255, 0.2);
 | 
						|
	border-radius: 50%;
 | 
						|
	display: flex;
 | 
						|
	align-items: center;
 | 
						|
	justify-content: center;
 | 
						|
	backdrop-filter: blur(20rpx);
 | 
						|
	box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2);
 | 
						|
	animation: pulse 2s ease-in-out infinite;
 | 
						|
}
 | 
						|
 | 
						|
.icon-text {
 | 
						|
	font-size: 60rpx;
 | 
						|
}
 | 
						|
 | 
						|
@keyframes pulse {
 | 
						|
	0%, 100% {
 | 
						|
		transform: scale(1);
 | 
						|
		box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2);
 | 
						|
	}
 | 
						|
	50% {
 | 
						|
		transform: scale(1.05);
 | 
						|
		box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.3);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
.loading-section {
 | 
						|
	display: flex;
 | 
						|
	flex-direction: column;
 | 
						|
	align-items: center;
 | 
						|
	margin-bottom: 80rpx;
 | 
						|
	animation: fadeInUp 1s ease-out 0.5s both;
 | 
						|
}
 | 
						|
 | 
						|
.loading-dots {
 | 
						|
	display: flex;
 | 
						|
	gap: 16rpx;
 | 
						|
	margin-bottom: 30rpx;
 | 
						|
}
 | 
						|
 | 
						|
.dot {
 | 
						|
	width: 16rpx;
 | 
						|
	height: 16rpx;
 | 
						|
	border-radius: 50%;
 | 
						|
	background: rgba(255, 255, 255, 0.3);
 | 
						|
	transition: all 0.3s ease;
 | 
						|
}
 | 
						|
 | 
						|
.dot.active {
 | 
						|
	background: #fff;
 | 
						|
	transform: scale(1.2);
 | 
						|
	box-shadow: 0 0 20rpx rgba(255, 255, 255, 0.5);
 | 
						|
}
 | 
						|
 | 
						|
.loading-text {
 | 
						|
	font-size: 28rpx;
 | 
						|
	color: rgba(255, 255, 255, 0.9);
 | 
						|
	font-weight: 500;
 | 
						|
	text-align: center;
 | 
						|
}
 | 
						|
 | 
						|
.version-info {
 | 
						|
	position: absolute;
 | 
						|
	bottom: 60rpx;
 | 
						|
	left: 50%;
 | 
						|
	transform: translateX(-50%);
 | 
						|
	animation: fadeInUp 1s ease-out 1s both;
 | 
						|
}
 | 
						|
 | 
						|
.version-text {
 | 
						|
	font-size: 24rpx;
 | 
						|
	color: rgba(255, 255, 255, 0.6);
 | 
						|
	text-align: center;
 | 
						|
}
 | 
						|
 | 
						|
@keyframes fadeInUp {
 | 
						|
	from {
 | 
						|
		opacity: 0;
 | 
						|
		transform: translateY(30rpx);
 | 
						|
	}
 | 
						|
	to {
 | 
						|
		opacity: 1;
 | 
						|
		transform: translateY(0);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* 响应式设计 */
 | 
						|
@media screen and (max-width: 750rpx) {
 | 
						|
	.logo-text {
 | 
						|
		font-size: 56rpx;
 | 
						|
	}
 | 
						|
	
 | 
						|
	.logo-icon {
 | 
						|
		width: 100rpx;
 | 
						|
		height: 100rpx;
 | 
						|
	}
 | 
						|
	
 | 
						|
	.icon-text {
 | 
						|
		font-size: 50rpx;
 | 
						|
	}
 | 
						|
}
 | 
						|
</style>
 |