Files
ebiz-ai-knowledge-manage/src/views/app/layout/components/Sidebar/Sidebar.vue
陈昱达 dd71e1c818 feat(intelligent-agent): 添加智能体可见权限功能
- 在智能体列表和详情页面添加可见权限相关功能
- 实现可见权限的 cascader 选择组件
- 添加用户选择功能,支持多选- 优化智能体创建和编辑页面,增加可见权限相关字段- 调整首页布局,移除不必要的元素
2025-05-09 17:56:55 +08:00

394 lines
9.5 KiB
Vue

<template>
<div class="sidebar-container">
<div class="sidebar-layout">
<!-- Left side - Primary menu -->
<div class="primary-menu">
<div>
<logo class="logo" :collapse="true" />
<div>
<svg-icon
style="font-size: 20px;margin:0;cursor: pointer"
@click.native="findMouseEnter"
icon-class="hide"
:class-name="sidebar.opened ? 'rate360' : 'rate180'"
></svg-icon>
</div>
<div
v-for="route in menuList"
class="primary-menu-item"
:class="{ active: activeParent === route.url }"
@click="selectParentMenu(route)"
>
<i
v-if="route.icon"
:class="[
route.icon,
{ iconfont: !route.icon.includes('el-icon') },
{ mb5: route.icon.includes('el-icon') }
]"
class=" fs22"
></i>
<img
v-else
:src="activeParent === route.url ? knowledgeActive : knowledge"
alt=""
class="mb5"
style="width: 20px"
/>
<span class="menu-title mt5">{{ route.menuName }}</span>
</div>
</div>
<div>
<personal />
</div>
</div>
<div :class="classObj">
<div class="submenu-container" v-if="currentSubmenu.length">
<!-- <div class="submenu-header">-->
<!-- <span>{{ currentParentTitle }}</span>-->
<!-- </div>-->
<el-scrollbar wrap-class="scrollbar-wrapper">
<div class="submenu-list" style="width: 160px">
<pre style="font-size: 12px; padding: 10px; display: none;">{{
JSON.stringify(currentSubmenu, null, 2)
}}</pre>
<div
v-for="subItem in currentSubmenu"
:key="subItem.id"
class="submenu-item"
:class="{ active: activeMenu === subItem.url }"
@click="navigateTo(subItem.url)"
>
<i
v-if="subItem.icon"
class="mr10"
:class="[
subItem.icon,
{ iconfont: !subItem.icon.includes('el-icon') }
]"
/>
<span>{{ subItem.menuName }}</span>
</div>
</div>
</el-scrollbar>
</div>
</div>
<!-- Right side - Submenu -->
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import Logo from './Logo'
import variables from '@/assets/sass/variables.scss'
import Personal from '@/views/app/layout/components/Sidebar/personal.vue'
import knowledge from '@/assets/images/knowledge.png'
import knowledgeActive from '@/assets/images/knowledgeActive.png'
export default {
components: { Personal, Logo },
computed: {
classObj() {
return {
hideChildSidebar: !this.sidebar.opened,
showChildSidebar: this.sidebar.opened
}
},
knowledge() {
return knowledge
},
knowledgeActive() {
return knowledgeActive
},
...mapGetters(['sidebar', 'sidebarList']),
routes() {
return this.$router.options.routes
},
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables
},
isCollapse() {
return !this.sidebar.opened
},
currentSubmenu() {
if (!this.activeParent) return []
const parent = this.menuList.find(item => item.url === this.activeParent)
return parent ? parent.children || [] : []
},
currentParentTitle() {
if (!this.activeParent) return ''
const parent = this.menuList.find(item => item.url === this.activeParent)
return parent && parent.meta ? parent.meta.title : ''
}
},
data() {
return {
menuList: [],
activeParent: null
}
},
methods: {
...mapActions({
setSidebarList: 'app/setSidebarList'
}),
formatList(menu, state, parentPath = null) {
menu.map(item => {
if (parentPath) {
item.url = '/' + parentPath + '/' + item.url
}
if (item.otherInfo1 == 0) {
item.name = item.menuName
item.alwaysShow = state
item.meta = {
title: item.menuName,
icon: item.img
}
if (item.children != null) {
this.formatList(item.children, undefined, item.url)
} else {
item.children = []
}
} else {
item.children = []
}
})
return menu
},
selectParentMenu(route) {
this.activeParent = route.url
if (!this.sidebar.opened) {
// this.$store.dispatch('app/toggleSideBar')
}
// If this parent has children, don't navigate
if (route.children && route.children.length > 0) {
// this.$store.dispatch('app/toggleSideBar')
// Optionally navigate to the first child
this.navigateTo(route.children[0].url)
} else {
// If no children, navigate to the parent route
this.navigateTo(route.url)
}
},
navigateTo(url) {
// this.$store.dispatch('app/toggleSideBar')
// if (this.sidebar.opened) {
// this.$store.dispatch('app/toggleSideBar')
// }
if (url && url !== this.$route.path) {
this.$router.push(url)
}
},
findMouseEnter() {
this.$store.dispatch('app/toggleSideBar')
// this.$store.dispatch('app/toggleSideBar')
},
findParentForCurrentRoute() {
const currentPath = this.$route.path
// Try to find the parent menu that contains the current route
for (const parent of this.menuList) {
// Check if current route is the parent itself
if (parent.url === currentPath) {
this.activeParent = parent.url
return
}
// Check if current route is one of the children
if (parent.children && parent.children.length) {
const childMatch = parent.children.find(
child =>
child.url === currentPath ||
currentPath.startsWith(child.url + '/')
)
if (childMatch) {
this.activeParent = parent.url
return
}
}
}
// If no match found, default to first menu item if available
if (this.menuList.length > 0 && !this.activeParent) {
this.activeParent = this.menuList[0].url
}
}
},
created() {
if (sessionStorage.token !== 'MockToken') {
// 获取路由数据
this.menuList = this.$store.state.app.sidebarList
} else {
// 从路由配置中获取顶级路由
this.menuList = this.routes.filter(route => {
// 只显示有 meta 和 children 的路由,并且不是隐藏的
return route.meta && route.children && !route.hidden
})
}
// 根据当前路由设置活动的父菜单
this.$nextTick(() => {
this.findParentForCurrentRoute()
})
},
watch: {
$route() {
// Update active parent when route changes
this.findParentForCurrentRoute()
}
}
}
</script>
<style scoped lang="scss">
.sidebar-container {
height: 100%;
background-color: #fff;
border-right: 1px solid #e6e6e6;
overflow: hidden;
display: flex;
flex-direction: column;
}
.sidebar-layout {
display: flex;
flex: 1;
overflow: hidden;
background-color: #fff;
border-radius: 6px;
}
.primary-menu {
width: 95px;
height: 100%;
position: relative;
overflow-y: auto;
background-color: #fff;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding-bottom: 16px;
.logo {
margin-top: 30px;
margin-bottom: 20px;
}
&:after {
content: ' ';
position: absolute;
border-right: 1px solid #ebeef2;
height: 100%;
right: 0;
top: 0;
bottom: 0;
transform: scaleX(0.5);
}
}
.primary-menu-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
//height: 58px;
//width: 68px;
padding: 10px;
cursor: pointer;
color: #606266;
margin-top: 10px;
&:hover,
&.active {
color: #4d64ff;
background-color: #f8f8fa;
border-radius: 8px;
}
&.active span {
color: #000;
font-weight: bold;
}
.svg-icon {
font-size: 24px;
margin-bottom: 8px;
}
.menu-title {
font-size: 14px;
text-align: center;
}
}
.submenu-container {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 23px 10px;
width: 160px;
}
.submenu-header {
height: 50px;
line-height: 50px;
padding: 0 20px;
font-size: 16px;
font-weight: bold;
border-bottom: 1px solid #f0f0f0;
}
.submenu-list {
padding: 10px 0;
}
.submenu-item {
height: 40px;
line-height: 40px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: flex-start;
cursor: pointer;
color: #000;
margin-bottom: 5px;
border-radius: 4px;
font-size: 14px;
&:hover,
&.active {
color: #4d64ff;
background-color: #f8f8fa;
}
&.active span {
color: #000;
font-weight: bold;
}
.svg-icon {
margin-right: 10px;
}
}
.scrollbar-wrapper {
height: 100%;
}
</style>