左侧导航烂优化

This commit is contained in:
yml2213
2026-05-14 22:27:48 +08:00
parent 8b399ae851
commit 36779bf672
2 changed files with 109 additions and 10 deletions
+1
View File
@@ -59,6 +59,7 @@ declare module 'vue' {
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
TencentAuthCard: typeof import('./components/tencent/TencentAuthCard.vue')['default'] TencentAuthCard: typeof import('./components/tencent/TencentAuthCard.vue')['default']
+108 -10
View File
@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { import {
Box, Box,
@@ -7,10 +7,13 @@ import {
Connection, Connection,
DataAnalysis, DataAnalysis,
Document, Document,
Expand,
Fold,
List, List,
Message, Message,
Service, Service,
Setting, Setting,
SwitchButton,
Tickets, Tickets,
User, User,
} from '@element-plus/icons-vue' } from '@element-plus/icons-vue'
@@ -22,6 +25,10 @@ import { formatAdminDateTime } from '@/utils/admin-time'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const sidebarStorageKey = 'admin-sidebar-collapsed'
const isSidebarCollapsed = ref(
typeof window !== 'undefined' && window.localStorage.getItem(sidebarStorageKey) === '1',
)
const currentRole = computed(() => getAdminRole()) const currentRole = computed(() => getAdminRole())
const isAdmin = computed(() => currentRole.value === 'admin') const isAdmin = computed(() => currentRole.value === 'admin')
@@ -71,6 +78,13 @@ const navItems = computed(() => {
return items return items
}) })
function toggleSidebarCollapse() {
isSidebarCollapsed.value = !isSidebarCollapsed.value
if (typeof window !== 'undefined') {
window.localStorage.setItem(sidebarStorageKey, isSidebarCollapsed.value ? '1' : '0')
}
}
async function submitLogout() { async function submitLogout() {
try { try {
await logoutAdmin() await logoutAdmin()
@@ -85,14 +99,26 @@ async function submitLogout() {
</script> </script>
<template> <template>
<div class="admin-page"> <div class="admin-page" :class="{ 'is-sidebar-collapsed': isSidebarCollapsed }">
<aside class="admin-sidebar"> <aside class="admin-sidebar">
<div class="sidebar-brand"> <div class="sidebar-brand">
<strong>运营后台</strong> <div v-if="!isSidebarCollapsed" class="brand-copy">
<p>订单与交付管理</p> <strong>运营后台</strong>
<p>订单与交付管理</p>
</div>
<el-tooltip :content="isSidebarCollapsed ? '展开导航' : '折叠导航'" placement="right">
<el-button
class="sidebar-toggle"
circle
:aria-label="isSidebarCollapsed ? '展开导航' : '折叠导航'"
@click="toggleSidebarCollapse"
>
<el-icon><component :is="isSidebarCollapsed ? Expand : Fold" /></el-icon>
</el-button>
</el-tooltip>
</div> </div>
<div class="sidebar-user"> <div v-if="!isSidebarCollapsed" class="sidebar-user">
<div class="user-name">{{ getAdminUsername() || '未读取' }}</div> <div class="user-name">{{ getAdminUsername() || '未读取' }}</div>
<div class="user-role">{{ roleLabel }}</div> <div class="user-role">{{ roleLabel }}</div>
<div class="user-expiry">有效期至 {{ formatAdminDateTime(getAdminTokenExpiresAt()) }}</div> <div class="user-expiry">有效期至 {{ formatAdminDateTime(getAdminTokenExpiresAt()) }}</div>
@@ -102,15 +128,27 @@ async function submitLogout() {
:default-active="route.path" :default-active="route.path"
router router
class="sidebar-menu" class="sidebar-menu"
:collapse="isSidebarCollapsed"
:collapse-transition="false"
:ellipsis="false" :ellipsis="false"
> >
<el-menu-item v-for="item in navItems" :key="item.to" :index="item.to"> <el-menu-item v-for="item in navItems" :key="item.to" :index="item.to" :title="item.label">
<el-icon><component :is="item.icon" /></el-icon> <el-icon><component :is="item.icon" /></el-icon>
<span>{{ item.label }}</span> <span>{{ item.label }}</span>
</el-menu-item> </el-menu-item>
</el-menu> </el-menu>
<el-button round class="logout-btn" @click="submitLogout">退出登录</el-button> <el-tooltip :disabled="!isSidebarCollapsed" content="退出登录" placement="right">
<el-button
class="logout-btn"
:circle="isSidebarCollapsed"
:round="!isSidebarCollapsed"
@click="submitLogout"
>
<el-icon v-if="isSidebarCollapsed"><SwitchButton /></el-icon>
<span v-else>退出登录</span>
</el-button>
</el-tooltip>
</aside> </aside>
<section class="admin-content"> <section class="admin-content">
@@ -123,13 +161,18 @@ async function submitLogout() {
.admin-page { .admin-page {
height: 100vh; height: 100vh;
display: grid; display: grid;
grid-template-columns: 260px minmax(0, 1fr); grid-template-columns: 232px minmax(0, 1fr);
overflow: hidden; overflow: hidden;
transition: grid-template-columns 0.18s ease;
background: background:
radial-gradient(circle at top left, rgba(73, 136, 255, 0.1), transparent 30%), radial-gradient(circle at top left, rgba(73, 136, 255, 0.1), transparent 30%),
linear-gradient(180deg, var(--bg-page) 0%, #edf3fb 100%); linear-gradient(180deg, var(--bg-page) 0%, #edf3fb 100%);
} }
.admin-page.is-sidebar-collapsed {
grid-template-columns: 72px minmax(0, 1fr);
}
.admin-sidebar { .admin-sidebar {
height: 100vh; height: 100vh;
display: flex; display: flex;
@@ -142,22 +185,36 @@ async function submitLogout() {
} }
.sidebar-brand { .sidebar-brand {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-3);
padding: 0 var(--space-5); padding: 0 var(--space-5);
margin-bottom: var(--space-4); margin-bottom: var(--space-4);
} }
.sidebar-brand strong { .brand-copy { min-width: 0; }
.brand-copy strong {
display: block; display: block;
font-size: var(--text-xl); font-size: var(--text-xl);
color: var(--text-primary); color: var(--text-primary);
} }
.sidebar-brand p { .brand-copy p {
margin: var(--space-2) 0 0; margin: var(--space-2) 0 0;
color: var(--text-secondary); color: var(--text-secondary);
font-size: var(--text-sm); font-size: var(--text-sm);
} }
.sidebar-toggle {
width: 34px;
height: 34px;
flex: 0 0 auto;
color: var(--text-secondary);
background: rgba(255, 255, 255, 0.72);
}
.sidebar-user { .sidebar-user {
margin: 0 var(--space-4) var(--space-4); margin: 0 var(--space-4) var(--space-4);
padding: var(--space-3); padding: var(--space-3);
@@ -186,6 +243,7 @@ async function submitLogout() {
border-right: none; border-right: none;
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
width: 100%;
} }
.sidebar-menu :deep(.el-menu-item) { .sidebar-menu :deep(.el-menu-item) {
@@ -205,6 +263,32 @@ async function submitLogout() {
flex-shrink: 0; flex-shrink: 0;
} }
.is-sidebar-collapsed .admin-sidebar {
align-items: stretch;
padding-top: var(--space-5);
}
.is-sidebar-collapsed .sidebar-brand {
justify-content: center;
padding: 0;
margin-bottom: var(--space-5);
}
.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item) {
justify-content: center;
margin: 4px 10px;
padding: 0;
}
.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item .el-icon) {
margin-right: 0;
}
.is-sidebar-collapsed .logout-btn {
width: 40px;
margin: var(--space-3) auto 0;
}
.admin-content { .admin-content {
min-width: 0; min-width: 0;
height: 100vh; height: 100vh;
@@ -220,6 +304,10 @@ async function submitLogout() {
overflow: visible; overflow: visible;
} }
.admin-page.is-sidebar-collapsed {
grid-template-columns: 1fr;
}
.admin-sidebar { .admin-sidebar {
height: auto; height: auto;
overflow: visible; overflow: visible;
@@ -228,8 +316,18 @@ async function submitLogout() {
padding-bottom: var(--space-4); padding-bottom: var(--space-4);
} }
.is-sidebar-collapsed .admin-sidebar {
padding-top: var(--space-4);
}
.sidebar-menu { overflow: visible; } .sidebar-menu { overflow: visible; }
.is-sidebar-collapsed .sidebar-menu :deep(.el-menu-item) {
justify-content: flex-start;
margin: 2px var(--space-2);
padding: 0 var(--space-5);
}
.admin-content { .admin-content {
height: auto; height: auto;
overflow: visible; overflow: visible;