Files
schoolNews/schoolNewsWeb/src/views/admin/AdminLayout.vue
2025-11-14 19:17:49 +08:00

174 lines
3.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="admin-layout">
<!-- 头部区域主标题和副标题 -->
<div class="admin-layout-header">
<div class="header-content">
<h1 class="main-title">{{ title }}</h1>
<p class="subtitle" v-if="subtitle">{{ subtitle }}</p>
</div>
</div>
<!-- 标签页导航当前路由的兄弟路由 -->
<div class="admin-layout-tabs" v-if="menus.length > 0">
<div class="tab-item-container">
<router-link
v-for="menu in menus"
:key="menu.path"
:to="getFullPath(menu)"
class="tab-item"
:class="{ active: isActive(menu) }"
>
<img
v-if="menu.meta?.icon"
:src="String(PUBLIC_IMG_PATH + '/' + menu.meta.icon)"
class="tab-icon"
:alt="String(menu.meta?.title || '')"
/>
<span class="tab-text">{{ menu.meta?.title }}</span>
</router-link>
</div>
</div>
<!-- 内容区域 -->
<div class="admin-layout-content">
<slot></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute, RouteRecordRaw } from 'vue-router';
import { getParentChildrenRoutes } from '@/utils/routeUtils';
import { PUBLIC_IMG_PATH} from '@/config'
// 定义 props
defineProps<{
title: string;
subtitle?: string;
}>();
const route = useRoute();
console.log(route.path);
// 获取兄弟路由(计算属性,确保响应式更新)
const menus = computed(() => {
return getParentChildrenRoutes(route);
});
console.log(menus.value);
// 获取完整路径
function getFullPath(menu: RouteRecordRaw): string {
// 如果路径是相对路径,需要拼接父路径
if (menu.path?.startsWith('/')) {
return menu.path;
}
// 获取父路径
const parentPath = route.matched.length >= 2
? route.matched[route.matched.length - 2].path
: '';
return `${parentPath}/${menu.path}`.replace(/\/+/g, '/');
}
// 判断是否为当前激活路由
function isActive(menu: RouteRecordRaw): boolean {
const fullPath = getFullPath(menu);
return route.path === fullPath || route.path.startsWith(fullPath + '/');
}
</script>
<style scoped lang="scss">
.admin-layout {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.admin-layout-header {
padding: 4px 0 24px 0;
.header-content {
.main-title {
font-size: 20px;
font-weight: 600;
margin: 0 0 4px 0;
line-height: 28px;
color: #1D2129;
}
.subtitle {
font-size: 14px;
margin: 0;
line-height: 22px;
color: #86909C;
}
}
}
.admin-layout-tabs {
display: flex;
gap: 0;
padding: 0;
overflow-x: auto;
margin-bottom: 24px;
.tab-item-container {
display: flex;
border-radius: 15px;
gap: 0;
overflow-x: auto;
}
&::-webkit-scrollbar {
height: 4px;
}
&::-webkit-scrollbar-thumb {
background-color: #C9CDD4;
border-radius: 2px;
}
.tab-item {
position: relative;
display: flex;
align-items: center;
background-color: #FFFFFF;
gap: 8px;
padding: 14px 20px;
font-size: 14px;
color: #4E5969;
text-decoration: none;
white-space: nowrap;
transition: all 0.2s ease;
border-bottom: 2px solid transparent;
.tab-icon {
width: 16px;
height: 16px;
object-fit: contain;
flex-shrink: 0;
}
.tab-text {
line-height: 1;
}
&:hover {
color: #165DFF;
}
&.active {
color: #165DFF;
font-weight: 500;
border-bottom-color: #165DFF;
}
}
}
.admin-layout-content {
flex: 1;
box-sizing: border-box;
}
</style>