| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- <template>
- <!-- 移动端横屏提示遮罩(全局统一) -->
- <div class="mobile-landscape-hint" :class="{ 'mobile-show': showLandscapeHint }">
- <div class="hint-icon">📱</div>
- <div class="hint-text">请横屏使用</div>
- <div class="hint-desc">为获得更好的体验,请将设备横屏放置</div>
- <button class="hint-close-btn" @click="closeLandscapeHint">知道了({{ countdown }}秒)</button>
- </div>
- <!-- 路由视图 -->
- <router-view></router-view>
- <footer v-if="isLoginPage" class="login-record-footer">
- <a
- href="https://beian.miit.gov.cn/#/Integrated/index"
- target="_blank"
- rel="noopener noreferrer"
- >
- ICP备案:京ICP备2025136397号-1
- </a>
- </footer>
- </template>
- <script setup>
- import { computed, ref, onMounted, onUnmounted, watch } from 'vue'
- import { useRoute } from 'vue-router'
- const route = useRoute()
- const showLandscapeHint = ref(false)
- const countdown = ref(3) // 倒计时初始值
- let countdownTimer = null
- const loginRoutes = new Set([
- '/',
- '/login',
- '/login-mobile',
- '/quick-login',
- '/promotion-login',
- '/login-qsfl',
- '/register-login',
- '/ai-login',
- '/blockly-login'
- ])
- const isLoginPage = computed(() => loginRoutes.has(route.path))
- let hasShownOnce = false // 用于跟踪当前会话中是否已经显示过提示
- // 检测是否为移动设备
- const isMobileDevice = () => {
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
- (window.innerWidth <= 768 && window.innerHeight <= 1024)
- }
- // 检测设备是否为横屏
- const isLandscape = () => {
- return window.innerWidth > window.innerHeight
- }
- // 检查当前路由是否为排除页面
- const isExcludedRoute = () => {
- return route.path.includes('/parent-mobile-course') ||
- route.path.includes('/parent-mobile-course-detail') ||
- route.path.includes('/login') ||
- route.path.includes('/ai-develop') ||
- route.path.includes('/ai-general-course')
- }
- // 关闭横屏提示
- const closeLandscapeHint = () => {
- showLandscapeHint.value = false
- hasShownOnce = true // 标记本次会话中已显示过提示
- // 清理倒计时定时器
- if (countdownTimer) {
- clearInterval(countdownTimer)
- countdownTimer = null
- }
- }
- // 开始倒计时
- const startCountdown = () => {
- // 重置倒计时
- countdown.value = 3
- // 清理之前的定时器
- if (countdownTimer) {
- clearInterval(countdownTimer)
- }
- // 开始新的倒计时
- countdownTimer = setInterval(() => {
- countdown.value--
- if (countdown.value <= 0) {
- closeLandscapeHint()
- }
- }, 1000)
- }
- // 检查是否应该显示横屏提示
- const checkLandscapeHint = () => {
- // 对于排除的路由,始终不显示横屏提示
- if (isExcludedRoute()) {
- showLandscapeHint.value = false
- return
- }
- if (isMobileDevice() && !isLandscape() && !isExcludedRoute() && !hasShownOnce) {
- // 如果是移动设备、竖屏、不在排除路由中,且本次会话中未显示过提示,则显示横屏提示
- showLandscapeHint.value = true
- // 开始倒计时
- startCountdown()
- }
- }
- // 监听窗口大小变化(仅处理屏幕旋转)
- const handleResize = () => {
- // 如果是由于旋转导致的横屏,则关闭提示
- if (isLandscape()) {
- closeLandscapeHint()
- } else {
- // 如果变为竖屏,且不在排除路由中,且本次会话中未显示过提示,则检查是否显示提示
- if (!isExcludedRoute() && isMobileDevice() && !hasShownOnce) {
- showLandscapeHint.value = true
- startCountdown()
- }
- }
- }
- // 监听路由变化
- watch(() => route.path, () => {
- // 如果进入排除路由,立即关闭提示
- if (isExcludedRoute()) {
- showLandscapeHint.value = false
- // 清理可能存在的倒计时
- if (countdownTimer) {
- clearInterval(countdownTimer)
- countdownTimer = null
- }
- }
- // 每次路由变化时都检查是否应该显示横屏提示
- checkLandscapeHint()
- }, { immediate: true })
- // 组件挂载时更新状态
- onMounted(() => {
- checkLandscapeHint() // 页面加载时检查
- window.addEventListener('resize', handleResize)
- // 监听设备方向变化(如果支持的话)
- if (window.screen && window.screen.orientation) {
- window.screen.orientation.addEventListener('change', handleResize)
- }
- })
- // 组件卸载时移除事件监听
- onUnmounted(() => {
- window.removeEventListener('resize', handleResize)
- if (window.screen && window.screen.orientation) {
- window.screen.orientation.removeEventListener('change', handleResize)
- }
- // 清理定时器
- if (countdownTimer) {
- clearInterval(countdownTimer)
- }
- })
- </script>
- <style scoped>
- /* 移动端横屏提示遮罩 */
- .mobile-landscape-hint {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0, 0, 0, 0.9);
- display: none;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- z-index: 9999;
- color: white;
- text-align: center;
- }
- .mobile-landscape-hint.mobile-show {
- display: flex;
- }
- .hint-icon {
- font-size: 60px;
- margin-bottom: 20px;
- }
- .hint-text {
- font-size: 24px;
- margin-bottom: 10px;
- font-weight: bold;
- }
- .hint-desc {
- font-size: 16px;
- opacity: 0.8;
- margin-bottom: 15px;
- }
- .hint-close-btn {
- background-color: #409eff;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 16px;
- margin-top: 10px;
- }
- .hint-close-btn:hover {
- background-color: #66b1ff;
- }
- .login-record-footer {
- position: fixed;
- right: 16px;
- bottom: 16px;
- left: 16px;
- z-index: 1000;
- text-align: center;
- }
- .login-record-footer a {
- color: rgba(255, 255, 255, 0.86);
- font-size: 12px;
- line-height: 1.5;
- text-decoration: none;
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
- }
- .login-record-footer a:hover,
- .login-record-footer a:focus-visible {
- color: #fff;
- text-decoration: underline;
- }
- /* 移动端样式 - 屏幕宽度小于 768px */
- @media (max-width: 768px) {
- .login-record-footer {
- right: 12px;
- bottom: 12px;
- left: 12px;
- }
- .login-record-footer a {
- font-size: 11px;
- }
- router-view {
- padding: 10px;
- }
- }
- /* PC 端样式 - 屏幕宽度大于 1200px */
- @media (min-width: 1200px) {
- router-view {
- padding: 20px;
- }
- }
- * {
- margin: 0;
- padding: 0;
- }
- html,
- body{
- width: 100vw;
- height: 100vh;
- overflow: hidden;
- }
- </style>
|