You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

166 lines
4.7 KiB

<template>
<el-container class="layout-container">
<el-aside :width="isCollapse ? '64px' : '220px'" class="layout-aside">
<div class="logo">
<span v-if="!isCollapse">企业AI平台</span>
<span v-else>AI</span>
</div>
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
router
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<el-menu-item index="/user/dashboard">
<el-icon><Monitor /></el-icon>
<span>工作台</span>
</el-menu-item>
<el-sub-menu index="ai-studio">
<template #title>
<el-icon><Cpu /></el-icon>
<span>AI 工作室</span>
</template>
<el-menu-item index="/user/chat/flow">流式对话</el-menu-item>
<el-menu-item index="/user/document/manager">文档处理</el-menu-item>
</el-sub-menu>
<el-sub-menu index="my-work">
<template #title>
<el-icon><List /></el-icon>
<span>我的工作</span>
</template>
<el-menu-item index="/user/task/list" v-if="can('task:read')">任务列表</el-menu-item>
<el-menu-item index="/user/notification/center">通知中心</el-menu-item>
</el-sub-menu>
<el-menu-item index="/user/profile">
<el-icon><User /></el-icon>
<span>个人中心</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<el-header class="layout-header">
<div class="header-left">
<el-button @click="isCollapse = !isCollapse" :icon="Fold" text />
<el-breadcrumb separator="/" style="margin-left: 16px">
<el-breadcrumb-item :to="{ path: '/user/dashboard' }">工作台</el-breadcrumb-item>
<el-breadcrumb-item v-if="route.meta.title">{{ route.meta.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="header-right">
<PortalSwitcher />
<el-dropdown @command="handleCommand">
<span class="user-info">
<el-icon><User /></el-icon>
{{ userStore.displayName || userStore.user?.username }}
<el-icon><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile">个人信息</el-dropdown-item>
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
<el-main class="layout-main">
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { Fold, User, ArrowDown, Cpu, Monitor } from '@element-plus/icons-vue'
import PortalSwitcher from '@/components/common/PortalSwitcher.vue'
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const isCollapse = ref(false)
const activeMenu = computed(() => {
const path = route.path
if (path.startsWith('/user/chat')) return '/user/chat/flow'
if (path.startsWith('/user/document')) return '/user/document/manager'
if (path.startsWith('/user/task')) return '/user/task/list'
if (path.startsWith('/user/notification')) return '/user/notification/center'
if (path.startsWith('/user/profile')) return '/user/profile'
return path
})
function can(code: string): boolean {
return userStore.hasPermission(code)
}
function handleCommand(cmd: string) {
if (cmd === 'profile') {
router.push('/user/profile')
} else if (cmd === 'logout') {
userStore.logout()
router.push('/login')
}
}
</script>
<style scoped>
.layout-container {
height: 100vh;
}
.layout-aside {
background-color: #304156;
overflow-y: auto;
transition: width 0.3s;
}
.logo {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 18px;
font-weight: bold;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.el-menu {
border-right: none;
}
.layout-header {
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e6e6e6;
height: 60px;
padding: 0 20px;
}
.header-left {
display: flex;
align-items: center;
}
.header-right {
display: flex;
align-items: center;
}
.user-info {
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
font-size: 14px;
}
.layout-main {
background: #f0f2f5;
padding: 20px;
overflow-y: auto;
}
</style>