|
|
@@ -0,0 +1,396 @@
|
|
|
+<template>
|
|
|
+ <div class="header-wrapper">
|
|
|
+ <div class="nav-bar-container">
|
|
|
+ <el-row type="flex" align="middle" class="nav-content">
|
|
|
+ <el-col :xs="3" :sm="2" :md="3" class="logo-wrapper">
|
|
|
+ <a href="/" class="logo-link">
|
|
|
+ <img src="@/assets/img/logo.png" class="logo-img" alt="logo">
|
|
|
+ <span class="logo-text hidden-xs-only">TNBAPP</span>
|
|
|
+ </a>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :sm="6" :md="7" class="hidden-xs-only">
|
|
|
+ <div class="nav-links">
|
|
|
+ <router-link to="/region" class="nav-item-link">分区</router-link>
|
|
|
+ <router-link to="/short" class="nav-item-link">短视频</router-link>
|
|
|
+ <router-link to="/playlist" class="nav-item-link">播放列表</router-link>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :xs="15" :sm="8" :md="6">
|
|
|
+ <div class="search-wrapper">
|
|
|
+ <el-autocomplete
|
|
|
+ v-model="keyword"
|
|
|
+ :fetch-suggestions="querySearchAsync"
|
|
|
+ :placeholder="searchHint"
|
|
|
+ prefix-icon="el-icon-search"
|
|
|
+ class="custom-search"
|
|
|
+ size="small"
|
|
|
+ @keyup.enter.native="onSearch"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :xs="6" :sm="8" :md="8" class="user-actions">
|
|
|
+ <div class="action-icons hidden-xs-only">
|
|
|
+ <div class="icon-item-wrapper" @click="goToTimeline">
|
|
|
+ <el-badge :value="statusCount" :max="99" :hidden="statusCount <= 0" class="badge-item">
|
|
|
+ <i class="el-icon-wind-power custom-icon"></i>
|
|
|
+ </el-badge>
|
|
|
+ <span class="icon-label">动态</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="icon-item-wrapper" @click="goToMessage">
|
|
|
+ <el-badge :value="msgCount" :max="99" :hidden="msgCount <= 0" class="badge-item">
|
|
|
+ <i class="el-icon-message-solid custom-icon"></i>
|
|
|
+ </el-badge>
|
|
|
+ <span class="icon-label">消息</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="user-profile-wrapper">
|
|
|
+ <el-dropdown v-if="user" trigger="hover" placement="bottom" class="user-dropdown-trigger">
|
|
|
+ <div class="avatar-wrapper">
|
|
|
+ <img :src="user.avatarUrl" class="user-avatar" alt="avatar">
|
|
|
+ </div>
|
|
|
+ <el-dropdown-menu slot="dropdown" class="user-dropdown-menu">
|
|
|
+ <div class="user-name-header">{{ user.screenName || '用户' }}</div>
|
|
|
+ <el-dropdown-item icon="el-icon-s-home" @click.native="goToUserHome">我的主页</el-dropdown-item>
|
|
|
+ <el-dropdown-item icon="el-icon-collection" @click.native="goToPlaylist">收藏列表</el-dropdown-item>
|
|
|
+ <el-dropdown-item icon="el-icon-collection" @click.native="goToHistory">历史记录</el-dropdown-item>
|
|
|
+ <el-dropdown-item icon="el-icon-collection" @click.native="goToBackground">进入后台</el-dropdown-item>
|
|
|
+ <el-dropdown-item icon="el-icon-switch-button" divided @click.native="goToLogout">退出登录</el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </el-dropdown>
|
|
|
+
|
|
|
+ <el-button v-else type="text" class="login-btn-text" @click="login">登录</el-button>
|
|
|
+
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ class="upload-btn-blue hidden-xs-only"
|
|
|
+ @click="goToPublish"
|
|
|
+ >
|
|
|
+ <i class="el-icon-upload"></i>
|
|
|
+ <span>投稿</span>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <nav class="bottom-nav hidden-sm-and-up">
|
|
|
+ <router-link to="/" class="bottom-nav-item" exact-active-class="is-active">
|
|
|
+ <i class="el-icon-house"></i>
|
|
|
+ <span>首页</span>
|
|
|
+ </router-link>
|
|
|
+ <router-link to="/region" class="bottom-nav-item" active-class="is-active">
|
|
|
+ <i class="el-icon-menu"></i>
|
|
|
+ <span>分区</span>
|
|
|
+ </router-link>
|
|
|
+ <router-link to="/short" class="bottom-nav-item" active-class="is-active">
|
|
|
+ <i class="el-icon-video-camera"></i>
|
|
|
+ <span>短视频</span>
|
|
|
+ </router-link>
|
|
|
+ <router-link :to="user ? `/timeline` : '/login'" class="bottom-nav-item" active-class="is-active">
|
|
|
+ <i class="el-icon-wind-power"></i>
|
|
|
+ <span>动态</span>
|
|
|
+ </router-link>
|
|
|
+ <router-link :to="user ? `/user/${user.userIdStr}` : '/login'" class="bottom-nav-item" active-class="is-active">
|
|
|
+ <i class="el-icon-user"></i>
|
|
|
+ <span>我的</span>
|
|
|
+ </router-link>
|
|
|
+ </nav>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { userMixin } from 'assets/js/mixin'
|
|
|
+import { keywordSuggest } from '@/api/search'
|
|
|
+import { getAuthedUser } from '@/utils/auth'
|
|
|
+import { getUnreadCount } from '@/api/user'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'NavBar',
|
|
|
+ mixins: [userMixin],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ user: null,
|
|
|
+ restaurants: [],
|
|
|
+ searchHint: '想要搜点神马呢',
|
|
|
+ keyword: '',
|
|
|
+ statusCount: 0,
|
|
|
+ msgCount: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ const userInfo = getAuthedUser()
|
|
|
+ if (userInfo !== null) {
|
|
|
+ this.user = userInfo
|
|
|
+ getUnreadCount().then(resp => {
|
|
|
+ if (resp.code === 0) {
|
|
|
+ this.msgCount = resp.data.total
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ querySearchAsync(queryString, cb) {
|
|
|
+ if (!queryString) return
|
|
|
+ setTimeout(() => {
|
|
|
+ keywordSuggest(queryString).then(res => {
|
|
|
+ if (res.code === 0) {
|
|
|
+ const results = res.data.map(item => ({ value: item.keyword }))
|
|
|
+ cb(results)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }, 300)
|
|
|
+ },
|
|
|
+ onSearch() {
|
|
|
+ if (this.keyword.trim()) {
|
|
|
+ this.toSearchPage()
|
|
|
+ } else {
|
|
|
+ this.$message.warning('不能为空!')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toSearchPage() {
|
|
|
+ const query = { keyword: this.keyword, pn: 1 }
|
|
|
+ if (this.$route.path === '/search') {
|
|
|
+ this.$router.push({ path: '/search', query }).catch(() => {})
|
|
|
+ } else {
|
|
|
+ const routeUrl = this.$router.resolve({ path: '/search', query })
|
|
|
+ window.open(routeUrl.href, '_blank')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ login() {
|
|
|
+ this.$router.push('/login').catch(() => {})
|
|
|
+ },
|
|
|
+ goToUserHome() { this.$router.push('/user/' + this.user.userIdStr) },
|
|
|
+ goToPlaylist() { this.$router.push('/bg/my/album') },
|
|
|
+ goToHistory() { this.$router.push('/bg/my/history') },
|
|
|
+ goToBackground() { this.$router.push('/bg') },
|
|
|
+ goToTimeline() { this.$router.push('/timeline') },
|
|
|
+ goToMessage() { this.$router.push('/bg/account/message') },
|
|
|
+ goToPublish() { this.$router.push('/bg/post/video') }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+/* 变量定义 */
|
|
|
+$primary-blue: #00a1d6;
|
|
|
+$hover-blue: #00b5e5;
|
|
|
+$text-main: #18191c;
|
|
|
+$text-second: #61666d;
|
|
|
+$bg-grey: #f1f2f3;
|
|
|
+
|
|
|
+/* 1. 顶部主容器 */
|
|
|
+.nav-bar-container {
|
|
|
+ position: fixed; /* 强制固定 */
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ z-index: 2000; /* 提高层级,确保在弹窗之下但在内容之上 */
|
|
|
+ height: 64px;
|
|
|
+ background: #fff;
|
|
|
+ /* 如果想要毛玻璃效果,取消下面两行的注释 */
|
|
|
+ /* background: rgba(255, 255, 255, 0.9); */
|
|
|
+ /* backdrop-filter: blur(10px); */
|
|
|
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-content {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 1400px;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+
|
|
|
+/* 2. Logo 样式 */
|
|
|
+.logo-link {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ text-decoration: none;
|
|
|
+ .logo-img { width: 30px; height: 30px; }
|
|
|
+ .logo-text {
|
|
|
+ color: $primary-blue;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 18px;
|
|
|
+ margin-left: 8px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 3. PC端菜单链接 */
|
|
|
+.nav-links {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+ .nav-item-link {
|
|
|
+ text-decoration: none;
|
|
|
+ color: $text-main;
|
|
|
+ font-size: 15px;
|
|
|
+ transition: color 0.2s;
|
|
|
+ &:hover { color: $primary-blue; }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 4. 搜索框美化 */
|
|
|
+.custom-search {
|
|
|
+ width: 100%;
|
|
|
+ ::v-deep .el-input__inner {
|
|
|
+ border-radius: 20px;
|
|
|
+ background-color: $bg-grey;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ padding-left: 35px;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ &:focus {
|
|
|
+ background-color: #fff;
|
|
|
+ border-color: $primary-blue;
|
|
|
+ box-shadow: 0 0 8px rgba(0, 161, 214, 0.15);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 5. 右侧操作区总布局 */
|
|
|
+.user-actions {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 图标组 (动态/消息) */
|
|
|
+.action-icons {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 20px;
|
|
|
+
|
|
|
+ .icon-item-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ margin-left: 18px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: transform 0.2s ease;
|
|
|
+
|
|
|
+ .custom-icon {
|
|
|
+ font-size: 20px;
|
|
|
+ color: $text-second;
|
|
|
+ transition: color 0.2s;
|
|
|
+ }
|
|
|
+ .icon-label {
|
|
|
+ font-size: 11px;
|
|
|
+ color: $text-second;
|
|
|
+ margin-top: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ .custom-icon, .icon-label { color: $primary-blue; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 头像与按钮包装 */
|
|
|
+.user-profile-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 8px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.user-avatar {
|
|
|
+ width: 36px;
|
|
|
+ height: 36px;
|
|
|
+ border-radius: 50%;
|
|
|
+ object-fit: cover;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ transition: all 0.3s;
|
|
|
+ &:hover {
|
|
|
+ transform: scale(1.1);
|
|
|
+ border-color: $primary-blue;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.login-btn-text {
|
|
|
+ color: $primary-blue;
|
|
|
+ font-weight: 500;
|
|
|
+ margin-right: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 蓝色投稿按钮 */
|
|
|
+.upload-btn-blue {
|
|
|
+ background-color: $primary-blue !important;
|
|
|
+ border: none !important;
|
|
|
+ border-radius: 8px !important;
|
|
|
+ height: 34px;
|
|
|
+ padding: 0 16px !important;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-left: 10px !important;
|
|
|
+ transition: all 0.3s !important;
|
|
|
+
|
|
|
+ i { font-size: 16px; margin-right: 4px; }
|
|
|
+ span { font-size: 14px; }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: $hover-blue !important;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 161, 214, 0.2);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 6. 移动端底部导航 */
|
|
|
+.bottom-nav {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ height: 56px;
|
|
|
+ background: rgba(255, 255, 255, 0.96);
|
|
|
+ backdrop-filter: blur(15px);
|
|
|
+ display: flex;
|
|
|
+ border-top: 1px solid #f1f2f3;
|
|
|
+ z-index: 2000;
|
|
|
+ padding-bottom: env(safe-area-inset-bottom);
|
|
|
+
|
|
|
+ .bottom-nav-item {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ text-decoration: none;
|
|
|
+ color: $text-second;
|
|
|
+ i { font-size: 20px; margin-bottom: 2px; }
|
|
|
+ span { font-size: 10px; }
|
|
|
+ &.is-active { color: $primary-blue; i { font-weight: bold; } }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 7. 移动端适配补丁 */
|
|
|
+@media screen and (max-width: 768px) {
|
|
|
+ .nav-bar-container { padding: 0 10px; height: 56px; }
|
|
|
+ .user-profile-wrapper { margin-right: 5px; }
|
|
|
+ .logo-wrapper { flex: 0 0 auto; width: 40px; }
|
|
|
+ .custom-search {
|
|
|
+ ::v-deep .el-input__inner { height: 32px; line-height: 32px; }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 下拉菜单修饰 */
|
|
|
+.user-dropdown-menu {
|
|
|
+ .user-name-header {
|
|
|
+ padding: 12px 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: $text-main;
|
|
|
+ border-bottom: 1px solid #f1f2f3;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|