Files
everything-is-suitable/everything-is-suitable-admin/src/layouts/DefaultLayout.vue
T
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

230 lines
5.8 KiB
Vue

<template>
<a-layout class="layout">
<a-layout-sider
v-model:collapsed="collapsed"
:trigger="null"
collapsible
:width="240"
:collapsed-width="64"
class="layout-sider"
>
<div class="logo">
<template v-if="!collapsed">
<span>管理系统</span>
</template>
<template v-else>
<span class="logo-icon">M</span>
</template>
</div>
<a-menu
v-model:selectedKeys="selectedKeys"
v-model:openKeys="openKeys"
mode="inline"
theme="dark"
:inline-collapsed="collapsed"
>
<a-menu-item key="dashboard" @click="handleMenuClick('/dashboard')">
<template #icon>
<DashboardOutlined />
</template>
<span>仪表盘</span>
</a-menu-item>
<a-sub-menu key="system">
<template #icon>
<SettingOutlined />
</template>
<template #title>系统管理</template>
<a-menu-item key="users" @click="handleMenuClick('/users')">
<template #icon>
<UserOutlined />
</template>
<span>用户管理</span>
</a-menu-item>
<a-menu-item key="roles" @click="handleMenuClick('/roles')">
<template #icon>
<LockOutlined />
</template>
<span>角色管理</span>
</a-menu-item>
<a-menu-item key="menus" @click="handleMenuClick('/menus')">
<template #icon>
<MenuOutlined />
</template>
<span>菜单管理</span>
</a-menu-item>
</a-sub-menu>
</a-menu>
</a-layout-sider>
<a-layout>
<a-layout-header class="header">
<div class="header-left">
<MenuUnfoldOutlined
v-if="collapsed"
class="trigger"
@click="toggleSidebar"
/>
<MenuFoldOutlined
v-else
class="trigger"
@click="toggleSidebar"
/>
<a-breadcrumb class="breadcrumb">
<a-breadcrumb-item>首页</a-breadcrumb-item>
<a-breadcrumb-item v-for="item in breadcrumbItems" :key="item">
{{ item }}
</a-breadcrumb-item>
</a-breadcrumb>
</div>
<div class="header-right">
<a-space>
<a-button type="text" :icon="h(BellOutlined)" />
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent>
<UserOutlined />
<span class="user-name">{{ user?.username || '用户' }}</span>
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<a-menu-item key="profile">
<UserOutlined />
个人中心
</a-menu-item>
<a-menu-item key="settings">
<SettingOutlined />
设置
</a-menu-item>
<a-menu-divider />
<a-menu-item key="logout" @click="handleLogout">
<LogoutOutlined />
退出登录
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-space>
</div>
</a-layout-header>
<a-layout-content class="content">
<div class="content-wrapper">
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</div>
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script setup lang="ts">
import { ref, computed, h } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { message } from 'ant-design-vue'
import { useAuthStore, useAppStore } from '../stores'
import {
DashboardOutlined,
SettingOutlined,
UserOutlined,
LockOutlined,
MenuOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined,
DownOutlined,
LogoutOutlined,
BellOutlined
} from '@ant-design/icons-vue'
const router = useRouter()
const route = useRoute()
const authStore = useAuthStore()
const appStore = useAppStore()
const collapsed = computed(() => appStore.sidebarCollapsed)
const selectedKeys = ref<string[]>(['dashboard'])
const openKeys = ref<string[]>(['system'])
const user = computed(() => authStore.user)
const breadcrumbItems = computed(() => {
const pathMap: Record<string, string> = {
'/dashboard': '仪表盘',
'/users': '用户管理',
'/roles': '角色管理',
'/menus': '菜单管理'
}
const items = []
const currentPath = route.path
if (pathMap[currentPath]) {
items.push(pathMap[currentPath])
}
return items
})
function toggleSidebar() {
appStore.toggleSidebar()
}
function handleMenuClick(path: string) {
router.push(path)
}
async function handleLogout() {
try {
await authStore.logout()
message.success('退出登录成功')
router.push('/login')
} catch (error) {
message.error('退出登录失败')
}
}
</script>
<style scoped lang="scss">
.layout {
min-height: 100vh;
.logo {
height: 32px;
margin: 16px;
color: white;
font-size: 18px;
font-weight: bold;
text-align: center;
}
.header {
background: white;
padding: 0 16px;
display: flex;
justify-content: space-between;
align-items: center;
.header-left {
.trigger {
font-size: 18px;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: #1890ff;
}
}
}
.header-right {
.ant-dropdown-link {
cursor: pointer;
}
}
}
.content {
margin: 16px;
padding: 24px;
background: white;
min-height: 280px;
}
}
</style>