Files
tyapi-frontend/src/layouts/MainLayout.vue
2025-12-12 18:09:14 +08:00

240 lines
6.2 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>
<el-container class="main-container">
<!-- 简化的页面背景 -->
<div class="page-background"></div>
<!-- 企业认证横幅 - 在header上方 -->
<CertificationBanner />
<el-header class="el-header">
<AppHeader
:title="headerTitle"
:badge="headerBadge"
:badge-type="headerBadgeType"
:theme="headerTheme"
@user-command="handleUserCommand"
/>
</el-header>
<el-container>
<!-- 桌面端显示侧边栏移动端隐藏移动端使用抽屉式侧边栏 -->
<el-aside v-if="!appStore.isMobile" width="240px">
<AppSidebar :menu-items="currentMenuItems" :theme="sidebarTheme" />
</el-aside>
<!-- 移动端也渲染侧边栏但使用固定定位的抽屉式效果 -->
<AppSidebar v-if="appStore.isMobile" :menu-items="currentMenuItems" :theme="sidebarTheme" />
<el-main :class="{ 'mobile-main': appStore.isMobile }">
<div class="content-wrapper">
<!-- 企业认证提示 - 根据当前页面路径显示 -->
<CertificationNotice
v-if="shouldShowCertificationNotice"
:show="true"
:title="certificationConfig?.title"
:description="certificationConfig?.description"
/>
<router-view />
</div>
</el-main>
</el-container>
<NotificationPanel
v-model:visible="showNotifications"
:title="notificationTitle"
:theme="notificationTheme"
/>
<!-- 右侧浮动联系客服 -->
<FloatingCustomerService />
</el-container>
</template>
<script setup>
import CertificationNotice from '@/components/common/CertificationNotice.vue'
import FloatingCustomerService from '@/components/common/FloatingCustomerService.vue'
import AppHeader from '@/components/layout/AppHeader.vue'
import AppSidebar from '@/components/layout/AppSidebar.vue'
import NotificationPanel from '@/components/layout/NotificationPanel.vue'
import { getCurrentPageCertificationConfig, getUserAccessibleMenuItems } from '@/constants/menu'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { ElMessageBox } from 'element-plus'
const router = useRouter()
const appStore = useAppStore()
const userStore = useUserStore()
const showNotifications = ref(false)
// 性能优化:检测设备性能
const isLowPerformanceDevice = computed(() => {
// 检测硬件并发数、内存等
const hardwareConcurrency = navigator.hardwareConcurrency || 4
const memory = navigator.deviceMemory || 4
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
return hardwareConcurrency <= 4 || memory <= 4 || isMobile
})
// 根据用户类型计算布局属性
const isAdmin = computed(() => userStore.isAdmin)
const headerTitle = computed(() => {
return isAdmin.value ? '天远数据控制台' : '天远数据控制台'
})
const headerBadge = computed(() => {
return isAdmin.value ? '管理员模式' : null
})
const headerBadgeType = computed(() => {
return isAdmin.value ? 'danger' : null
})
const headerTheme = computed(() => {
return isAdmin.value ? 'admin' : 'user'
})
const sidebarTheme = computed(() => {
return isAdmin.value ? 'admin' : 'user'
})
const notificationTitle = computed(() => {
return isAdmin.value ? '系统通知' : '通知'
})
const notificationTheme = computed(() => {
return isAdmin.value ? 'admin' : 'user'
})
// 动态菜单项
const currentMenuItems = computed(() => {
return getUserAccessibleMenuItems(userStore.userType, userStore.isCertified)
})
// 认证相关逻辑
const currentRoute = computed(() => router.currentRoute.value)
const certificationConfig = computed(() => {
return getCurrentPageCertificationConfig(currentRoute.value.path)
})
const shouldShowCertificationNotice = computed(() => {
console.log(certificationConfig.value, userStore.isCertified)
// 如果页面不需要认证,不显示提示
if (!certificationConfig.value) {
return false
}
// 如果用户已认证,不显示提示
if (userStore.isCertified) {
return false
}
// 如果是管理员页面,不显示提示
// if (isAdmin.value) {
// return false
// }
return true
})
// 处理用户菜单命令
const handleUserCommand = async (command) => {
switch (command) {
case 'home':
window.open('https://www.tianyuanapi.com/', '_blank', 'noopener')
break
case 'profile':
router.push('/profile')
break
case 'settings':
if (isAdmin.value) {
router.push('/admin/system')
} else {
router.push('/profile/settings')
}
break
case 'switchToUser':
if (isAdmin.value) {
router.push('/products')
}
break
case 'logout':
try {
await ElMessageBox.confirm('确定要退出登录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
userStore.logout()
router.push('/auth/login')
} catch {
// 用户取消
}
break
}
}
</script>
<style scoped>
.page-background {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 50%, #f8fafc 100%);
}
.main-container {
height: 100vh;
background: transparent;
}
.el-header {
padding: 0;
}
.content-wrapper {
padding: 16px;
}
.el-main {
background: transparent;
padding: 0;
transition: margin-left 0.3s ease;
}
/* 移动端内容区域全宽显示 */
.mobile-main {
width: 100% !important;
margin-left: 0 !important;
}
/* 性能优化:为低端设备提供简化样式 */
@media (max-width: 768px) {
.content-wrapper {
padding: 0 12px 12px 12px;
}
/* 确保移动端容器全宽 */
.el-container {
width: 100%;
}
}
/* 性能优化:减少动画效果 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 性能优化:低端设备降级 */
@media (max-width: 768px), (max-device-pixel-ratio: 1) {
.page-background {
background: #f8fafc;
}
}
</style>