385 lines
9.5 KiB
Vue
385 lines
9.5 KiB
Vue
<script setup>
|
|
import { ref, computed, watch } from 'vue'
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
import { useUserStore } from '../stores/user'
|
|
import { usePlayerStore } from '../stores/player'
|
|
import { Search } from '@element-plus/icons-vue'
|
|
import MusicPlayer from '../components/MusicPlayer.vue'
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const userStore = useUserStore()
|
|
const playerStore = usePlayerStore()
|
|
const activeIndex = ref('/')
|
|
const searchKeyword = ref('')
|
|
|
|
// 监听路由变化,更新激活的菜单项
|
|
watch(() => route.path, (newPath) => {
|
|
activeIndex.value = newPath
|
|
}, { immediate: true })
|
|
|
|
const isLoggedIn = computed(() => userStore.isLoggedIn)
|
|
|
|
// 处理搜索
|
|
const handleSearch = () => {
|
|
if (!searchKeyword.value.trim()) return
|
|
|
|
router.push({
|
|
path: '/search',
|
|
query: { keyword: searchKeyword.value }
|
|
})
|
|
|
|
// 搜索后清空搜索框
|
|
searchKeyword.value = ''
|
|
}
|
|
|
|
// 跳转到登录页面
|
|
const goToLogin = () => {
|
|
router.push('/login')
|
|
}
|
|
|
|
// 导航到个人中心
|
|
const goToUserCenter = () => {
|
|
router.push('/user')
|
|
}
|
|
|
|
// 导航到后台管理
|
|
const goToAdmin = () => {
|
|
router.push('/admin')
|
|
}
|
|
|
|
// 退出登录
|
|
const logout = () => {
|
|
userStore.logout()
|
|
router.push('/')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="main-layout">
|
|
<el-container>
|
|
<el-header>
|
|
<div class="header-content">
|
|
<div class="logo">音乐应用</div>
|
|
<!-- 自定义导航菜单 -->
|
|
<div class="custom-nav">
|
|
<router-link to="/" class="nav-item" :class="{ 'active': activeIndex === '/' }">首页</router-link>
|
|
<router-link to="/music" class="nav-item" :class="{ 'active': activeIndex === '/music' }">音乐</router-link>
|
|
<router-link to="/playlist" class="nav-item" :class="{ 'active': activeIndex === '/playlist' }">歌单</router-link>
|
|
<router-link to="/singer" class="nav-item" :class="{ 'active': activeIndex === '/singer' }">歌手</router-link>
|
|
<router-link to="/user" class="nav-item" :class="{ 'active': activeIndex === '/user' }" v-if="isLoggedIn">个人中心</router-link>
|
|
</div>
|
|
|
|
<div class="header-right">
|
|
<div class="search-box">
|
|
<el-input
|
|
v-model="searchKeyword"
|
|
placeholder="搜索音乐、歌单、歌手"
|
|
clearable
|
|
@keyup.enter="handleSearch"
|
|
>
|
|
<template #suffix>
|
|
<el-icon class="el-input__icon" @click="handleSearch">
|
|
<Search />
|
|
</el-icon>
|
|
</template>
|
|
</el-input>
|
|
</div>
|
|
|
|
<div class="user-actions">
|
|
<template v-if="isLoggedIn">
|
|
<el-dropdown>
|
|
<span class="el-dropdown-link">
|
|
{{ userStore.user?.nickname || userStore.user?.username }}
|
|
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
|
</span>
|
|
<template #dropdown>
|
|
<el-dropdown-menu>
|
|
<el-dropdown-item v-if="userStore.user?.role === 1" @click="goToAdmin">后台管理</el-dropdown-item>
|
|
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
|
|
</el-dropdown-menu>
|
|
</template>
|
|
</el-dropdown>
|
|
</template>
|
|
<template v-else>
|
|
<el-button type="primary" size="small" @click="goToLogin">登录</el-button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-header>
|
|
|
|
<el-main>
|
|
<div class="content-container">
|
|
<router-view />
|
|
</div>
|
|
</el-main>
|
|
|
|
<!-- 音乐播放器 -->
|
|
<div class="player-container">
|
|
<MusicPlayer />
|
|
</div>
|
|
</el-container>
|
|
</div>
|
|
</template>
|
|
|
|
|
|
|
|
<style scoped>
|
|
.main-layout {
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden; /* 防止出现双滚动条 */
|
|
}
|
|
|
|
.el-container {
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden; /* 防止出现双滚动条 */
|
|
}
|
|
|
|
.el-header {
|
|
padding: 0;
|
|
/* background-color: rgba(255, 255, 255, 0.8); /* 半透明白色背景 */
|
|
background: linear-gradient(to bottom, rgba(255, 240, 245, 0.9), rgba(230, 247, 255, 0.9)); /* 淡粉到淡蓝的半透明渐变 */
|
|
backdrop-filter: blur(5px); /* 添加模糊效果 */
|
|
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.08); /* 调整阴影 */
|
|
height: auto !important;
|
|
min-height: 70px;
|
|
position: sticky; /* 使 header 固定在顶部 */
|
|
top: 0;
|
|
z-index: 100; /* 确保在最上层 */
|
|
}
|
|
|
|
.header-content {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 30px; /* 增加左右内边距 */
|
|
position: relative;
|
|
height: 70px;
|
|
}
|
|
|
|
.logo {
|
|
font-size: 1.6rem; /* 稍大字体 */
|
|
font-weight: 600;
|
|
color: #ff6b81; /* 可爱粉色 */
|
|
z-index: 20;
|
|
text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.5); /* 添加轻微文字阴影 */
|
|
}
|
|
|
|
/* 自定义导航菜单样式 */
|
|
.custom-nav {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
display: flex;
|
|
justify-content: center;
|
|
z-index: 10;
|
|
height: 70px;
|
|
line-height: 70px;
|
|
}
|
|
|
|
.custom-nav .nav-item {
|
|
display: inline-block;
|
|
padding: 0 20px; /* 调整内边距 */
|
|
font-size: 1rem; /* 调整字体大小 */
|
|
font-weight: 500;
|
|
color: #555; /* 深灰色 */
|
|
text-decoration: none;
|
|
transition: all 0.3s ease;
|
|
height: 70px;
|
|
line-height: 70px;
|
|
min-width: 80px; /* 调整最小宽度 */
|
|
text-align: center;
|
|
position: relative; /* 为下划线定位 */
|
|
border-radius: 5px; /* 添加轻微圆角 */
|
|
}
|
|
|
|
.custom-nav .nav-item::after { /* 添加下划线动画效果 */
|
|
content: '';
|
|
position: absolute;
|
|
width: 0;
|
|
height: 3px;
|
|
bottom: 15px; /* 调整下划线位置 */
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
background-color: #ffb6c1; /* 淡粉色 */
|
|
transition: width 0.3s ease;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.custom-nav .nav-item:hover {
|
|
color: #ff6b81; /* 悬停时粉色 */
|
|
background-color: rgba(255, 255, 255, 0.3); /* 悬停时轻微背景 */
|
|
}
|
|
|
|
.custom-nav .nav-item:hover::after {
|
|
width: 60%; /* 悬停时显示下划线 */
|
|
}
|
|
|
|
.custom-nav .nav-item.active {
|
|
color: #ff6b81; /* 激活时粉色 */
|
|
font-weight: 600; /* 激活时加粗 */
|
|
}
|
|
|
|
.custom-nav .nav-item.active::after {
|
|
width: 60%; /* 激活时显示下划线 */
|
|
background-color: #ff6b81; /* 激活时下划线颜色加深 */
|
|
}
|
|
|
|
|
|
/* 移除旧的 Element Plus 导航样式 (如果不再使用) */
|
|
.main-nav .el-menu-item { display: none !important; }
|
|
|
|
|
|
.header-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 25px; /* 增加间距 */
|
|
z-index: 20;
|
|
}
|
|
|
|
.search-box .el-input__wrapper { /* 美化搜索框 */
|
|
border-radius: 20px !important;
|
|
background-color: rgba(255, 255, 255, 0.7) !important;
|
|
box-shadow: none !important;
|
|
border: 1px solid #eee;
|
|
}
|
|
.search-box .el-input__inner {
|
|
color: #555;
|
|
}
|
|
.search-box .el-input__icon {
|
|
color: #aaa;
|
|
cursor: pointer;
|
|
}
|
|
.search-box .el-input__icon:hover {
|
|
color: #ff6b81;
|
|
}
|
|
|
|
|
|
.user-actions .el-button { /* 美化登录按钮 */
|
|
border-radius: 20px;
|
|
background-color: #ffb6c1;
|
|
border-color: #ffb6c1;
|
|
color: white;
|
|
}
|
|
.user-actions .el-button:hover {
|
|
background-color: #ff8a9b;
|
|
border-color: #ff8a9b;
|
|
}
|
|
|
|
.el-dropdown-link {
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
color: #555; /* 用户名颜色 */
|
|
font-weight: 500;
|
|
}
|
|
.el-dropdown-link:hover {
|
|
color: #ff6b81; /* 悬停时粉色 */
|
|
}
|
|
.el-dropdown-menu__item:hover {
|
|
background-color: #fff0f5 !important; /* 下拉菜单悬停背景 */
|
|
color: #ff6b81 !important; /* 下拉菜单悬停文字颜色 */
|
|
}
|
|
|
|
.el-main {
|
|
padding: 10px;
|
|
background: linear-gradient(to bottom, #fff0f5, #e6f7ff); /* 淡粉到淡蓝的渐变 */
|
|
flex: 1;
|
|
margin-bottom: 0; /* 移除底部边距 */
|
|
padding-bottom: 100px; /* 增加底部填充,为播放器留出空间 */
|
|
overflow: hidden; /* 禁用外层滚动 */
|
|
height: calc(100vh - 70px - 80px); /* 减去头部和播放器高度 */
|
|
position: relative;
|
|
}
|
|
|
|
/* 内容容器样式 - 将内容限制在70%宽度并居中 */
|
|
.content-container {
|
|
width: 70%;
|
|
margin: 0 auto;
|
|
height: 100%;
|
|
background-color: transparent;
|
|
box-sizing: border-box;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
/* 隐藏滚动条 */
|
|
scrollbar-width: none; /* Firefox */
|
|
-ms-overflow-style: none; /* IE and Edge */
|
|
}
|
|
|
|
/* 隐藏Webkit浏览器的滚动条 */
|
|
.content-container::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
|
|
|
|
/* 音乐播放器容器样式 */
|
|
.player-container {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 80px;
|
|
z-index: 1000;
|
|
background-color: #fff; /* 添加背景色 */
|
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
|
|
}
|
|
|
|
/* 响应式样式 */
|
|
@media screen and (max-width: 1200px) {
|
|
.custom-nav .nav-item {
|
|
padding: 0 12px;
|
|
min-width: 60px;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.content-container {
|
|
width: 85%;
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: 992px) {
|
|
.custom-nav {
|
|
position: relative;
|
|
left: auto;
|
|
transform: none;
|
|
justify-content: center;
|
|
width: 100%;
|
|
margin: 10px 0;
|
|
flex-wrap: wrap; /* 允许菜单项换行 */
|
|
}
|
|
|
|
.custom-nav .nav-item {
|
|
padding: 0 10px;
|
|
min-width: 50px;
|
|
font-size: 14px;
|
|
height: 40px;
|
|
line-height: 40px;
|
|
}
|
|
|
|
.header-content {
|
|
flex-direction: column;
|
|
padding: 10px 20px;
|
|
}
|
|
|
|
.logo {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.header-right {
|
|
margin-top: 10px;
|
|
width: 100%;
|
|
justify-content: center;
|
|
}
|
|
|
|
.content-container {
|
|
width: 95%;
|
|
}
|
|
}
|
|
</style>
|