Generating commit message...
This commit is contained in:
350
admin-system/src/layouts/MainLayout.vue
Normal file
350
admin-system/src/layouts/MainLayout.vue
Normal file
@@ -0,0 +1,350 @@
|
||||
<template>
|
||||
<a-layout class="main-layout">
|
||||
<!-- 侧边栏 -->
|
||||
<a-layout-sider
|
||||
v-model:collapsed="collapsed"
|
||||
:trigger="null"
|
||||
collapsible
|
||||
:width="240"
|
||||
class="layout-sider"
|
||||
>
|
||||
<div class="logo">
|
||||
<img src="@/assets/logo.png" alt="Logo" v-if="!collapsed" />
|
||||
<h1 v-if="!collapsed">结伴客管理</h1>
|
||||
<span v-else>JK</span>
|
||||
</div>
|
||||
|
||||
<a-menu
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
theme="dark"
|
||||
mode="inline"
|
||||
:inline-collapsed="collapsed"
|
||||
>
|
||||
<a-menu-item key="dashboard">
|
||||
<template #icon>
|
||||
<DashboardOutlined />
|
||||
</template>
|
||||
<span>仪表板</span>
|
||||
<router-link to="/dashboard" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="users">
|
||||
<template #icon>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
<span>用户管理</span>
|
||||
<router-link to="/users" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="merchants">
|
||||
<template #icon>
|
||||
<ShopOutlined />
|
||||
</template>
|
||||
<span>商家管理</span>
|
||||
<router-link to="/merchants" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="travel">
|
||||
<template #icon>
|
||||
<CompassOutlined />
|
||||
</template>
|
||||
<span>旅行管理</span>
|
||||
<router-link to="/travel" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="animals">
|
||||
<template #icon>
|
||||
<HeartOutlined />
|
||||
</template>
|
||||
<span>动物管理</span>
|
||||
<router-link to="/animals" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="orders">
|
||||
<template #icon>
|
||||
<ShoppingCartOutlined />
|
||||
</template>
|
||||
<span>订单管理</span>
|
||||
<router-link to="/orders" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="promotion">
|
||||
<template #icon>
|
||||
<GiftOutlined />
|
||||
</template>
|
||||
<span>推广管理</span>
|
||||
<router-link to="/promotion" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item key="system">
|
||||
<template #icon>
|
||||
<SettingOutlined />
|
||||
</template>
|
||||
<span>系统设置</span>
|
||||
<router-link to="/system" />
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<a-layout>
|
||||
<!-- 顶部导航 -->
|
||||
<a-layout-header class="layout-header">
|
||||
<div class="header-left">
|
||||
<menu-unfold-outlined
|
||||
v-if="collapsed"
|
||||
class="trigger"
|
||||
@click="() => (collapsed = !collapsed)"
|
||||
/>
|
||||
<menu-fold-outlined
|
||||
v-else
|
||||
class="trigger"
|
||||
@click="() => (collapsed = !collapsed)"
|
||||
/>
|
||||
<a-breadcrumb class="breadcrumb">
|
||||
<a-breadcrumb-item>首页</a-breadcrumb-item>
|
||||
<a-breadcrumb-item>{{ currentRouteMeta.title }}</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<a-space :size="16">
|
||||
<a-tooltip title="消息">
|
||||
<a-badge :count="5" dot>
|
||||
<bell-outlined class="header-icon" />
|
||||
</a-badge>
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="帮助文档">
|
||||
<question-circle-outlined class="header-icon" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-dropdown :trigger="['click']">
|
||||
<a-avatar
|
||||
size="small"
|
||||
:src="userAvatar"
|
||||
class="avatar"
|
||||
/>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item>
|
||||
<user-outlined />
|
||||
<span>个人中心</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<setting-outlined />
|
||||
<span>账户设置</span>
|
||||
</a-menu-item>
|
||||
<a-menu-divider />
|
||||
<a-menu-item @click="handleLogout">
|
||||
<logout-outlined />
|
||||
<span>退出登录</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
||||
<span class="username">{{ userName }}</span>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-layout-header>
|
||||
|
||||
<!-- 页面内容 -->
|
||||
<a-layout-content class="layout-content">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="fade" mode="out-in">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import {
|
||||
DashboardOutlined,
|
||||
UserOutlined,
|
||||
ShopOutlined,
|
||||
CompassOutlined,
|
||||
HeartOutlined,
|
||||
ShoppingCartOutlined,
|
||||
GiftOutlined,
|
||||
SettingOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
MenuFoldOutlined,
|
||||
BellOutlined,
|
||||
QuestionCircleOutlined,
|
||||
LogoutOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const collapsed = ref(false)
|
||||
const selectedKeys = ref<string[]>(['dashboard'])
|
||||
|
||||
// 计算属性
|
||||
const currentRouteMeta = computed(() => route.meta || {})
|
||||
const userName = computed(() => appStore.state.user?.nickname || '管理员')
|
||||
const userAvatar = computed(() => appStore.state.user?.avatar || 'https://api.dicebear.com/7.x/miniavs/svg?seed=admin')
|
||||
|
||||
// 监听路由变化
|
||||
router.afterEach((to) => {
|
||||
selectedKeys.value = [to.name as string]
|
||||
})
|
||||
|
||||
// 退出登录
|
||||
const handleLogout = () => {
|
||||
Modal.confirm({
|
||||
title: '确认退出',
|
||||
content: '您确定要退出登录吗?',
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk() {
|
||||
appStore.logout()
|
||||
message.success('退出成功')
|
||||
router.push('/login')
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.main-layout {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.layout-sider {
|
||||
box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
|
||||
z-index: 10;
|
||||
|
||||
.logo {
|
||||
height: 64px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
margin: 16px;
|
||||
border-radius: 6px;
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-menu-dark) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
:deep(.ant-menu-item) {
|
||||
margin: 4px 0;
|
||||
border-radius: 6px;
|
||||
|
||||
&.ant-menu-item-selected {
|
||||
background: #1890ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 24px;
|
||||
background: white;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.trigger {
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
margin-right: 16px;
|
||||
color: #666;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
.header-icon {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
cursor: pointer;
|
||||
background: #1890ff;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-content {
|
||||
padding: 24px;
|
||||
background: #f5f5f5;
|
||||
min-height: calc(100vh - 64px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.layout-header {
|
||||
padding: 0 16px;
|
||||
|
||||
.header-left {
|
||||
.breadcrumb {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
.username {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.layout-content {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user