08ea5fbe98
添加用户管理视图、API和状态管理文件
230 lines
5.8 KiB
Vue
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>
|