Files
web/admin/src/layouts/AdminLayout.vue

139 lines
4.5 KiB
Vue

<template>
<el-container class="admin-layout">
<el-aside width="200px" class="sidebar">
<div class="logo">管理后台</div>
<el-menu
:default-active="$route.path"
router
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<template v-for="item in menuItems" :key="item.index">
<el-menu-item v-if="!item.children" :index="item.index">
<el-icon><component :is="item.icon" /></el-icon>
<span>{{ item.title }}</span>
</el-menu-item>
<el-sub-menu v-else :index="item.index">
<template #title>
<el-icon><component :is="item.icon" /></el-icon>
<span>{{ item.title }}</span>
</template>
<el-menu-item v-for="sub in item.children" :key="sub.index" :index="sub.index">{{ sub.title }}</el-menu-item>
</el-sub-menu>
</template>
</el-menu>
</el-aside>
<el-container>
<el-header class="header">
<span>多站点管理后台</span>
<div class="header-right">
<span class="username">{{ authStore.getUser()?.username }}</span>
<el-button link type="danger" @click="handleLogout">退出</el-button>
</div>
</el-header>
<el-main class="main">
<router-view />
</el-main>
<footer class="layout-footer">成都宇惠达智能科技有限公司 <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">蜀ICP备2025134957号-1</a></footer>
</el-container>
</el-container>
</template>
<script setup>
import { computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { House, User, Folder, ChatDotRound, Setting, Wallet, Monitor, Document, EditPen, Upload, Key, VideoCamera } from '@element-plus/icons-vue'
import { useAuthStore } from '../stores/auth'
import { getMyPermissions } from '../api/admin'
const router = useRouter()
const authStore = useAuthStore()
onMounted(async () => {
if (authStore.isLoggedIn()) {
try {
const res = await getMyPermissions()
authStore.setPermissions(res.permissions || [])
} catch (_) {}
}
})
const menuItems = computed(() => {
const hasPermission = (key) => !key || authStore.hasPermission(key)
const all = [
{ index: '/', title: '控制台', icon: House, permission: null },
{ index: '/users', title: '用户管理', icon: User, permission: 'user:manage' },
{ index: '/workspaces', title: '工作空间', icon: Folder, permission: 'workspace:manage' },
{ index: '/conversations', title: '对话管理', icon: ChatDotRound, permission: 'conversation:manage' },
{ index: '/sms-config', title: '短信配置', icon: Setting, permission: 'sms_config' },
{ index: '/payment-config', title: '支付配置', icon: Wallet, permission: 'payment_config' },
{ index: '/sites', title: '站点管理', icon: Monitor, permission: 'site:manage' },
{ index: '/pages', title: '网页管理', icon: Document, permission: 'page:manage' },
{ index: '/homepage-edit', title: '首页编辑', icon: EditPen, permission: 'homepage:edit' },
{ index: '/live-broadcast', title: '视频直播开播', icon: VideoCamera, permission: 'homepage:edit' },
{ index: '/files', title: '文件管理', icon: Folder, permission: null },
{ index: '/role-permissions', title: '角色权限管理', icon: Key, permission: 'role:permission' }
]
return all.filter((item) => {
if (item.children) {
item.children = item.children.filter((sub) => hasPermission(sub.permission))
return hasPermission(item.permission) && item.children.length > 0
}
return hasPermission(item.permission)
})
})
const handleLogout = () => {
authStore.logout()
router.push('/login')
}
</script>
<style scoped>
.admin-layout {
height: 100vh;
}
.sidebar {
background: #304156;
}
.logo {
height: 50px;
line-height: 50px;
text-align: center;
color: #fff;
font-weight: bold;
background: #263445;
}
.header {
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
}
.header-right {
display: flex;
align-items: center;
gap: 12px;
}
.username {
color: #666;
font-size: 14px;
}
.main {
background: #f0f2f5;
padding: 20px;
}
.layout-footer {
padding: 8px 20px;
font-size: 12px;
color: #999;
text-align: center;
border-top: 1px solid #eee;
}
.layout-footer a { color: #999; text-decoration: none; }
.layout-footer a:hover { text-decoration: underline; }
</style>