aigc-h5/src/layouts/Header.vue

290 lines
8.9 KiB
Vue

<template>
<div class="header">
<div class="logo">
<img :src="website.info.web_logo" :alt="website.info.web_title">
</div>
<div class="title">{{$route.meta.title}}</div>
<div class="nav">
<div class="navBtn" @click.stop="toggleMenu"><van-icon name="wap-nav" size="0.6rem" /></div>
<div class="menuBox" @click.stop="" v-if="showMenu">
<template v-if="userInfo.userData && userInfo.userData.id">
<div class="menuHeader">
<div class="userInfo">
<div class="avatar"><img :src="userInfo.userData.avatar || defaultAvatar"></div>
<div class="name">{{ userInfo.userData.name || userInfo.userData.phone || userInfo.userData.email }}</div>
</div>
<div class="navIcon" @click="toggleMenu"><van-icon name="wap-nav" size="0.6rem" /></div>
</div>
<ul class="menu">
<li :class="{ active: route.meta.group === 'home' }" @click="jump('/')">首页</li>
<li :class="{ active: route.meta.group === 'chat' }" @click="jump('/chat')">AI助理</li>
<li :class="{ active: route.meta.group === 'business' }" @click="jump('/business')">AI商情</li>
<li :class="{ active: route.meta.group === 'communication' }" @click="jump('/communication')">AI传播</li>
<li>AI献策</li>
<li :class="{ active: route.meta.group === 'vip' }" @click="jump('/vip')">会员服务</li>
<li :class="{ active: route.meta.group === 'ucenter' }" @click="jump('/ucenter/userinfo')">个人中心</li>
<li @click="onLogout">退出登录</li>
</ul>
</template>
<template v-else>
<div class="menuHeader">
<div class="userInfo">
<div class="avatar"><img src="" alt=""></div>
<div class="name">未登录</div>
</div>
<div class="navIcon" @click="toggleMenu"><van-icon name="wap-nav" size=".6rem" /></div>
</div>
<ul class="menu">
<li @click="onLogin">登录</li>
<li @click="onRegister"></li>
</ul>
</template>
</div>
</div>
<Auth />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useUserInfo } from '@/stores/userInfo';
import { localCache } from '@/io/cache';
import http from '@/io/http';
import { useRouter, useRoute } from 'vue-router';
import { showToast } from 'vant';
import Auth from '@/components/auth/index.vue';
import { useAuthModal } from '@/stores/authModal';
import { useWebsite } from '@/stores/website';
const website = useWebsite();
const userInfo = useUserInfo();
const router = useRouter();
const route = useRoute();
const authModal = useAuthModal();
const timer = ref(0);
const showMenu = ref(false);
onMounted(()=>{
document.body.addEventListener('click', ()=>{
showMenu.value = false;
});
let userInfoData = localCache.get('userInfo') || {};
if (userInfoData.id) {
userInfo.updateUserInfo(userInfoData);
}
let authData = localCache.get('auth') || {};
if (authData.expires_time) {
checkToken();
}
});
const checkToken = () => {
let diffTime = 1000 * 60 * 10; // 10mins
let nowTime = Date.now();
let authData = localCache.get('auth') || {};
let overTime = authData.expires_time || nowTime;
if (overTime - nowTime <= diffTime) {
clearTimeout(timer.value);
flushtoken();
} else {
timer.value = setTimeout(checkToken, 300000); //300000
}
};
const flushtoken = () => {
http('/api/auth/refresh', {}).then(res => {
let nowTime = Date.now();
let overTime = nowTime + res.data.expires_in * 1000;
let authData = { ...res.data, expires_time: overTime };
localCache.set('auth', authData);
checkToken();
}).catch(err => {
showToast(err.message);
});
};
const toggleMenu = ()=>{
showMenu.value = !showMenu.value;
};
const onLogin = ()=>{
showMenu.value = false;
authModal.setAuthModalType('login');
authModal.showAuthModal();
};
const onRegister = ()=>{
showMenu.value = false;
authModal.setAuthModalType('register');
authModal.showAuthModal();
};
const onLogout = ()=>{
showMenu.value = false;
http('/api/auth/logout').then(res => {
localCache.remove('userInfo');
localCache.remove('auth');
userInfo.updateUserInfo({});
showToast('已退出登录!');
window.location.replace('/');
}).catch(err => {
showToast(err.message);
})
};
const jump = (url)=>{
showMenu.value = false;
router.push(url);
}
</script>
<style lang="scss" scoped>
.header{
width: 100%;
height: 90px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 5px solid #3662FE;
background: #161718;
color: #FFF;
padding: 10px;
box-sizing: border-box;
position: relative;
z-index: 9;
.logo{
width: 230px;
height: 80px;
display: flex;
justify-content: flex-start;
align-items: center;
img{
object-fit: contain;
max-width: 100%;
max-height: 100%;
}
}
.title{
width: 230px;
height: 70px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 28px;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
}
.nav{
width: 230px;
height: 70px;
display: flex;
justify-content: flex-end;
align-items: center;
position: relative;
.navBtn{
width: 68px;
height: 68px;
background-color: #3662FE;
display: flex;
justify-content: center;
align-items: center;
color: #FFF;
}
}
.menuBox{
width: 400px;
background: #242527;
box-sizing: border-box;
position: absolute;
top: 0;
right: 0rem;
z-index: 5;
.menuHeader{
height: 70px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.userInfo{
flex: 1;
display: flex;
justify-content: flex-start;
align-items: center;
padding-left: 30px;
overflow: hidden;
.avatar{
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
background: #E9E9E9;
img{
width: 100%;
object-fit: contain;
}
}
.name{
flex: 1;
height: 70px;
line-height: 70px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 23px;
margin-left: 15px;
font-weight: bold;
}
}
.navIcon{
width: 68px;
height: 68px;
display: flex;
justify-content: center;
align-items: center;
}
}
.menu{
padding-bottom: 30px;
li{
height: 50px;
padding: 15px 0;
box-sizing: content-box;
line-height: 50px;
flex: 1;
font-size: 28px;
color: #ccc;
padding-left: 30px;
position: relative;
&::before{
content: '';
width: 7px;
height: 30px;
background-color: #3662FE;
transform: translateX(-30px);
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
display: none;
}
&:active,
&.active{
color: #FFF;
&::before{
display: block;
}
}
&:active{
background-color: rgb(255, 255, 255, .1);
}
}
}
}
}
</style>