GPU_Web/src/views/layout/index.vue
2026-01-06 14:20:31 +08:00

202 lines
7.0 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="gx_layout">
<div :class="isHome ? 'gx_layout_header_home' : 'gx_layout_header_noHome'" class="gx_layout_header">
<div class="logo">GxDL算力云</div>
<div class="menu">
<a-menu v-model:selectedKeys="current" :class="isHome ? 'custom-menu' : ''" mode="horizontal"
:items="leftRoutes" @click="({ key }) => handleMenuClick(key)" />
<a-menu v-model:selectedKeys="current" mode="horizontal" :class="isHome ? 'custom-menu' : ''"
:items="rightRoutes" @click="({ key }) => handleMenuClick(key)" />
</div>
<div class="user-info">
<template v-if="!isLogin">
<a-button type="primary" @click="router.push('/login')">登录 / 注册</a-button>
</template>
<template v-else>
<a-dropdown>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<a-avatar :size="24" :src="userInfo.avatar ?? avatar">
<!-- <template #icon>
<UserOutlined />
</template> -->
</a-avatar>
<span style="font-size: 14px;padding-left:5px;">{{ userInfo.userName }}</span>
</div>
<template #overlay>
<a-card hoverable style="width: 300px">
<template #cover>
<div style="background:#f5f7fa;padding:10px;line-height: 30px;display: flex;align-items: center;">
<div>
<img :src="avatar" alt="" srcset="" width="50">
</div>
<div style="margin-left: 10px;">
<div>{{ userInfo.phone }} <a-tag color="blue"
style="margin-left: 10px;">{{
userInfo.accountType === 'USER' ? '个人账户' : '企业账户' }}</a-tag></div>
<div>用户ID:{{ userInfo.id }}</div>
</div>
</div>
<div style="padding: 10px;line-height: 45px;">
<div style="display: flex;justify-content: space-between;align-items: center;">
<div>可用余额¥{{ userInfo.balance}}</div>
<!-- <a-button type="primary" danger ghost size="small">去充值</a-button> -->
</div>
<div>未读消息{{ userInfo.unreadMsgNum }}</div>
</div>
</template>
<template #actions>
<!-- <setting-outlined key="setting" />
<edit-outlined key="edit" />
<ellipsis-outlined key="ellipsis" /> -->
<a-button block type="text" @click="logout">退出登录</a-button>
</template>
</a-card>
</template>
</a-dropdown>
</template>
</div>
</div>
<div style="height: 60px;width: 100%;"></div>
<div class="gx_layout_content">
<router-view />
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { UserOutlined } from '@ant-design/icons-vue';
import avatar from '@/assets/avator.png'
const router = useRouter()
const route = useRoute()
const isHome = ref(true)
const isLogin = ref(!!localStorage.getItem('token'))
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
console.log('用户信息:', userInfo);
// 根据当前路由初始化菜单选中项(去掉 /layout 前缀)
const getActiveKeyFromRoute = () => {
const path = route.path
if (path.startsWith('/layout')) {
const key = path.replace('/layout', '') || '/home'
return [key.startsWith('/') ? key : '/' + key]
}
return ['/home']
}
const current = ref(getActiveKeyFromRoute())
// 监听路由变化(浏览器前进后退时同步菜单)
watch(() => route.path, () => {
current.value = getActiveKeyFromRoute()
if (current.value == '/home') {
isHome.value = true
} else {
isHome.value = true
}
})
// 菜单数据key 使用子路径,如 '/admin'
const leftRoutes = ref([
{ key: '/home', label: '首页' },
{ key: '/market', label: '算力中心' },
{ key: '/yingxiao', label: '营销活动' }
])
const rightRoutes = ref([
{ key: '/document', label: '用户文档' },
{ key: '/admin/home', label: '控制台' }
])
// 点击菜单跳转
const handleMenuClick = (key) => {
if (key === '/document') {
window.open(key, '_blank');
} else {
// 否则按照正常方式在当前标签页跳转
const fullPath = `/layout${key}`;
router.push(fullPath);
}
}
const logout = () => {
localStorage.clear()
router.replace('/login')
}
</script>
<style lang="scss" scoped>
.gx_layout {
width: 100%;
height: 100vh;
.gx_layout_header_home {
background-color: #cfe7fe;
border-bottom: none;
}
.gx_layout_header_noHome {
border-bottom: 1px solid rgb(216 216 216);
}
.gx_layout_header {
z-index: 999;
width: 100%;
height: 60px;
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
flex: 1;
.logo {
width: 200px;
}
.user-info {
width: 100px;
}
.menu {
flex: 1;
display: flex;
justify-content: space-around;
align-items: center;
&>ul:first-child {
width: 100%;
border-bottom: none;
}
&>ul {
border-bottom: none;
}
}
}
.gx_layout_content {
// margin-top: 60px;
// height: calc(100% - 60px);
min-height: calc(100% - 60px);
background-color: rgba(240, 240, 240, 1);
}
}
/* 自定义菜单主题 */
.custom-menu {
/* 背景色 */
background: #cfe7fe !important;
}
/* 选中项文字颜色 + 左侧竖条horizontal 模式下是底部横线) */
.custom-menu :deep(.ant-menu-item-selected) {
color: #2563eb !important;
}
/* hover 效果 */
.custom-menu :deep(.ant-menu-item:hover) {
color: #2563eb !important;
}
</style>