优化后台侧栏导航分类

This commit is contained in:
yml2213
2026-06-07 10:42:31 +08:00
parent 8e7c181b27
commit 53eb4acad8
+164 -11
View File
@@ -1,25 +1,32 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
Bell, Bell,
Briefcase,
ChatDotRound, ChatDotRound,
Coin,
DataLine, DataLine,
Document, Document,
DocumentChecked, DocumentChecked,
Operation,
Fold,
Expand, Expand,
Fold,
House,
Lock,
Money, Money,
Operation,
ScaleToOriginal, ScaleToOriginal,
Service,
Shop, Shop,
Setting,
SwitchButton, SwitchButton,
Tickets, Tickets,
Tools,
User, User,
UserFilled, UserFilled,
Wallet, Wallet,
Setting,
CreditCard CreditCard
} from '@element-plus/icons-vue' } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage, ElSubMenu } from 'element-plus'
import type { Component } from 'vue'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
@@ -35,37 +42,112 @@ const updatingStatus = ref(false)
interface NavItem { interface NavItem {
label: string label: string
to: string to: string
icon: any icon: Component
permission?: string permission?: string
} }
const allNavItems: NavItem[] = [ interface NavGroup {
label: string
index: string
icon: Component
children: NavItem[]
}
const allNavGroups: NavGroup[] = [
{
label: '工作台',
index: 'workspace',
icon: House,
children: [
{ label: '仪表盘', to: '/admin/dashboard', icon: DataLine, permission: 'dashboard:view' }, { label: '仪表盘', to: '/admin/dashboard', icon: DataLine, permission: 'dashboard:view' },
],
},
{
label: '业务管理',
index: 'business',
icon: Briefcase,
children: [
{ label: '用户管理', to: '/admin/users', icon: User, permission: 'user:view' }, { label: '用户管理', to: '/admin/users', icon: User, permission: 'user:view' },
{ label: '订单管理', to: '/admin/orders', icon: Tickets, permission: 'order:view' }, { label: '订单管理', to: '/admin/orders', icon: Tickets, permission: 'order:view' },
{ label: '商品管理', to: '/admin/listings', icon: Shop, permission: 'listing:view' }, { label: '商品管理', to: '/admin/listings', icon: Shop, permission: 'listing:view' },
{ label: '商品审核', to: '/admin/listings/review', icon: DocumentChecked, permission: 'listing:approve' }, { label: '商品审核', to: '/admin/listings/review', icon: DocumentChecked, permission: 'listing:approve' },
],
},
{
label: '客服与风控',
index: 'support-risk',
icon: Service,
children: [
{ label: '仲裁中心', to: '/admin/disputes', icon: ScaleToOriginal, permission: 'dispute:view' }, { label: '仲裁中心', to: '/admin/disputes', icon: ScaleToOriginal, permission: 'dispute:view' },
{ label: '客服群聊', to: '/admin/chats', icon: ChatDotRound, permission: 'chat:view' }, { label: '客服群聊', to: '/admin/chats', icon: ChatDotRound, permission: 'chat:view' },
],
},
{
label: '财务管理',
index: 'finance',
icon: Coin,
children: [
{ label: '资金流水', to: '/admin/wallet-ledger', icon: Wallet, permission: 'wallet:view' }, { label: '资金流水', to: '/admin/wallet-ledger', icon: Wallet, permission: 'wallet:view' },
{ label: '提现审核', to: '/admin/withdrawals', icon: Money, permission: 'withdrawal:list' }, { label: '提现审核', to: '/admin/withdrawals', icon: Money, permission: 'withdrawal:list' },
{ label: '支付配置', to: '/admin/payment-configs', icon: CreditCard, permission: 'payment_config:list' }, { label: '支付配置', to: '/admin/payment-configs', icon: CreditCard, permission: 'payment_config:list' },
],
},
{
label: '内容与配置',
index: 'content-config',
icon: Tools,
children: [
{ label: '公告管理', to: '/admin/announcements', icon: Bell, permission: 'announcement:view' }, { label: '公告管理', to: '/admin/announcements', icon: Bell, permission: 'announcement:view' },
{ label: '系统配置', to: '/admin/system-configs', icon: Operation, permission: 'system_config:view' }, { label: '系统配置', to: '/admin/system-configs', icon: Operation, permission: 'system_config:view' },
],
},
{
label: '系统权限',
index: 'system-auth',
icon: Lock,
children: [
{ label: '审计日志', to: '/admin/audit-logs', icon: Document, permission: 'audit_log:view' }, { label: '审计日志', to: '/admin/audit-logs', icon: Document, permission: 'audit_log:view' },
{ label: '管理员管理', to: '/admin/admin-users', icon: UserFilled, permission: 'admin_user:manage' }, { label: '管理员管理', to: '/admin/admin-users', icon: UserFilled, permission: 'admin_user:manage' },
{ label: '角色管理', to: '/admin/roles', icon: Setting, permission: 'role:manage' }, { label: '角色管理', to: '/admin/roles', icon: Setting, permission: 'role:manage' },
],
},
] ]
const navItems = computed(() => { const allNavItems = allNavGroups.flatMap((group) => group.children)
if (adminSession.isSuperAdmin) return allNavItems
return allNavItems.filter((item) => { function canAccessNavItem(item: NavItem) {
if (adminSession.isSuperAdmin) return true
if (!item.permission) return true if (!item.permission) return true
return adminSession.hasPermission(item.permission) return adminSession.hasPermission(item.permission)
}
const navGroups = computed(() => {
return allNavGroups
.map((group) => ({
...group,
children: group.children.filter((item) => canAccessNavItem(item)),
}))
.filter((group) => group.children.length > 0)
}) })
const activeMenu = computed(() => {
const currentPath = route.path
const matchedItem = allNavItems
.slice()
.sort((a, b) => b.to.length - a.to.length)
.find((item) => currentPath === item.to || currentPath.startsWith(`${item.to}/`))
return matchedItem?.to || currentPath
})
const defaultOpeneds = computed(() => {
const activeGroup = allNavGroups.find((group) =>
group.children.some((item) => item.to === activeMenu.value)
)
return activeGroup ? [activeGroup.index] : []
}) })
const activeMenu = computed(() => route.path)
const adminName = computed(() => adminSession.nickname || adminSession.username || '管理员') const adminName = computed(() => adminSession.nickname || adminSession.username || '管理员')
const supportStatus = computed(() => adminSession.supportStatus || 'offline') const supportStatus = computed(() => adminSession.supportStatus || 'offline')
const hasChatPermission = computed(() => adminSession.hasPermission('chat:view')) const hasChatPermission = computed(() => adminSession.hasPermission('chat:view'))
@@ -124,15 +206,28 @@ async function handleLogout() {
<el-menu <el-menu
:default-active="activeMenu" :default-active="activeMenu"
:default-openeds="defaultOpeneds"
:collapse="isCollapsed" :collapse="isCollapsed"
:collapse-transition="false" :collapse-transition="false"
unique-opened
router router
class="admin-menu" class="admin-menu"
> >
<el-menu-item v-for="item in navItems" :key="item.to" :index="item.to"> <el-sub-menu
v-for="group in navGroups"
:key="group.index"
:index="group.index"
popper-class="admin-menu-popper"
>
<template #title>
<el-icon><component :is="group.icon" /></el-icon>
<span>{{ group.label }}</span>
</template>
<el-menu-item v-for="item in group.children" :key="item.to" :index="item.to">
<el-icon><component :is="item.icon" /></el-icon> <el-icon><component :is="item.icon" /></el-icon>
<template #title>{{ item.label }}</template> <template #title>{{ item.label }}</template>
</el-menu-item> </el-menu-item>
</el-sub-menu>
</el-menu> </el-menu>
</aside> </aside>
@@ -259,6 +354,11 @@ async function handleLogout() {
} }
.admin-menu { .admin-menu {
--el-menu-bg-color: transparent;
--el-menu-text-color: #bfcbd9;
--el-menu-active-color: #409eff;
--el-menu-hover-bg-color: #263445;
flex: 1; flex: 1;
min-height: 0; min-height: 0;
border-right: none; border-right: none;
@@ -271,6 +371,22 @@ async function handleLogout() {
width: 100%; width: 100%;
} }
:deep(.el-menu) {
background-color: transparent;
}
:deep(.el-sub-menu__title) {
color: #bfcbd9;
}
:deep(.el-sub-menu__title:hover) {
background-color: #263445;
}
:deep(.el-sub-menu.is-active > .el-sub-menu__title) {
color: #409eff;
}
:deep(.el-menu-item) { :deep(.el-menu-item) {
color: #bfcbd9; color: #bfcbd9;
} }
@@ -284,6 +400,43 @@ async function handleLogout() {
background-color: #263445; background-color: #263445;
} }
:deep(.el-menu--inline) {
background-color: #263445;
}
:deep(.el-menu--inline .el-menu-item) {
height: 46px;
background-color: #263445;
font-size: 14px;
}
:deep(.el-menu--inline .el-menu-item:hover),
:deep(.el-menu--inline .el-menu-item.is-active) {
background-color: #1f2d3d;
}
:global(.admin-menu-popper) {
--el-menu-bg-color: #304156;
--el-menu-text-color: #bfcbd9;
--el-menu-active-color: #409eff;
--el-menu-hover-bg-color: #263445;
}
:global(.admin-menu-popper .el-menu) {
border-right: none;
background-color: #304156;
}
:global(.admin-menu-popper .el-menu-item) {
color: #bfcbd9;
}
:global(.admin-menu-popper .el-menu-item:hover),
:global(.admin-menu-popper .el-menu-item.is-active) {
color: #409eff;
background-color: #263445;
}
.admin-workspace { .admin-workspace {
flex: 1; flex: 1;
min-width: 0; min-width: 0;