优化后台侧栏导航分类
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user