2025-11-24 16:06:44 +08:00
|
|
|
|
<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>
|
2025-12-09 15:12:06 +08:00
|
|
|
|
<!-- 桌面端显示侧边栏,移动端隐藏(移动端使用抽屉式侧边栏) -->
|
|
|
|
|
|
<el-aside v-if="!appStore.isMobile" width="240px">
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<AppSidebar :menu-items="currentMenuItems" :theme="sidebarTheme" />
|
|
|
|
|
|
</el-aside>
|
2025-12-09 15:12:06 +08:00
|
|
|
|
<!-- 移动端也渲染侧边栏,但使用固定定位的抽屉式效果 -->
|
|
|
|
|
|
<AppSidebar v-if="appStore.isMobile" :menu-items="currentMenuItems" :theme="sidebarTheme" />
|
|
|
|
|
|
<el-main :class="{ 'mobile-main': appStore.isMobile }">
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<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'
|
2025-12-09 15:12:06 +08:00
|
|
|
|
import { useAppStore } from '@/stores/app'
|
2025-11-24 16:06:44 +08:00
|
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
|
|
|
import { ElMessageBox } from 'element-plus'
|
|
|
|
|
|
|
|
|
|
|
|
const router = useRouter()
|
2025-12-09 15:12:06 +08:00
|
|
|
|
const appStore = useAppStore()
|
2025-11-24 16:06:44 +08:00
|
|
|
|
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) {
|
2025-12-12 18:09:14 +08:00
|
|
|
|
case 'home':
|
|
|
|
|
|
window.open('https://www.tianyuanapi.com/', '_blank', 'noopener')
|
|
|
|
|
|
break
|
2025-11-24 16:06:44 +08:00
|
|
|
|
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;
|
2025-12-09 15:12:06 +08:00
|
|
|
|
transition: margin-left 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 移动端内容区域全宽显示 */
|
|
|
|
|
|
.mobile-main {
|
|
|
|
|
|
width: 100% !important;
|
|
|
|
|
|
margin-left: 0 !important;
|
2025-11-24 16:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 性能优化:为低端设备提供简化样式 */
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.content-wrapper {
|
|
|
|
|
|
padding: 0 12px 12px 12px;
|
|
|
|
|
|
}
|
2025-12-09 15:12:06 +08:00
|
|
|
|
|
|
|
|
|
|
/* 确保移动端容器全宽 */
|
|
|
|
|
|
.el-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
2025-11-24 16:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 性能优化:减少动画效果 */
|
|
|
|
|
|
@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>
|