You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
paopao-ce/web/src/components/sidebar.vue

416 lines
11 KiB

<template>
<div class="sidebar-wrap">
<div class="logo-wrap">
<n-image class="logo-img" width="36" :src="LOGO" :preview-disabled="true" @click="goHome" />
</div>
<n-menu :accordion="true" :icon-size="24" :options="menuOptions" :render-label="renderMenuLabel"
:render-icon="renderMenuIcon" :value="selectedPath" @update:value="goRouter" />
<div class="user-wrap" v-if="store.state.userInfo.id > 0">
<n-avatar class="user-avatar" round :size="34" :src="store.state.userInfo.avatar" />
<div class="user-info">
<div class="nickname">
<span class="nickname-txt">
{{ store.state.userInfo.nickname }}
</span>
<n-button class="logout" quaternary circle size="tiny" @click="handleLogout">
<template #icon>
<n-icon>
<log-out-outline />
</n-icon>
</template>
</n-button>
</div>
<div class="username">@{{ store.state.userInfo.username }}</div>
</div>
<div class="user-mini-wrap">
<n-button class="logout" quaternary circle @click="handleLogout">
<template #icon>
<n-icon :size="24">
<log-out-outline />
</n-icon>
</template>
</n-button>
</div>
</div>
<div class="user-wrap" v-else>
<div v-if="!allowUserRegister" class="login-only-wrap">
<n-button strong secondary round type="primary" @click="triggerAuth('signin')">
</n-button>
</div>
<div v-if="allowUserRegister" class="login-wrap">
<n-button strong secondary round type="primary" @click="triggerAuth('signin')">
</n-button>
<n-button strong secondary round type="info" @click="triggerAuth('signup')">
</n-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { h, ref, watch, computed, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useStore } from 'vuex';
import { NIcon, NBadge, useMessage } from 'naive-ui';
import {
HomeOutline,
BookmarksOutline,
MegaphoneOutline,
ChatbubblesOutline,
LeafOutline,
PeopleOutline,
WalletOutline,
SettingsOutline,
LogOutOutline,
} from '@vicons/ionicons5';
import { Hash } from '@vicons/tabler';
import { getUnreadMsgCount } from '@/api/user';
import LOGO from '@/assets/img/logo.png';
const store = useStore();
const route = useRoute();
const router = useRouter();
const hasUnreadMsg = ref(false);
const selectedPath = ref<any>(route.name || '');
const msgLoop = ref();
const useFrindship = (import.meta.env.VITE_USE_FRIENDSHIP.toLowerCase() === 'true');
const enableAnnoucement = (import.meta.env.VITE_ENABLE_ANOUNCEMENT.toLowerCase() === 'true');
const enableWallet = (import.meta.env.VITE_ENABLE_WALLET.toLocaleLowerCase() === 'true');
const allowUserRegister = ref(import.meta.env.VITE_ALLOW_USER_REGISTER.toLowerCase() === 'true');
const defMsgLoopInterval = Number(import.meta.env.VITE_DEFAULT_MSG_LOOP_INTERVAL);
watch(route, () => {
selectedPath.value = route.name;
});
watch(store.state, () => {
hasUnreadMsg.value = store.state.unreadMsgCount > 0;
if (store.state.userInfo.id > 0) {
if (!msgLoop.value) {
getUnreadMsgCount()
.then((res) => {
hasUnreadMsg.value = res.count > 0;
store.commit("updateUnreadMsgCount", res.count)
})
.catch((err) => {
console.log(err);
});
msgLoop.value = setInterval(() => {
getUnreadMsgCount()
.then((res) => {
hasUnreadMsg.value = res.count > 0;
store.commit("updateUnreadMsgCount", res.count)
})
.catch((err) => {
console.log(err);
});
}, defMsgLoopInterval);
}
} else {
if (msgLoop.value) {
clearInterval(msgLoop.value);
}
}
});
onMounted(() => {
window.onresize = () => {
store.commit('triggerCollapsedLeft', document.body.clientWidth <= 821);
store.commit('triggerCollapsedRight', document.body.clientWidth <= 821);
};
});
const menuOptions = computed(() => {
const options = [
{
label: '广',
key: 'home',
icon: () => h(HomeOutline),
href: '/',
},
{
label: '',
key: 'topic',
icon: () => h(Hash),
href: '/topic',
},
];
if (enableAnnoucement) {
options.push({
label: '',
key: 'anouncement',
icon: () => h(MegaphoneOutline),
href: '/anouncement',
});
}
options.push({
label: '',
key: 'profile',
icon: () => h(LeafOutline),
href: '/profile',
});
options.push({
label: '',
key: 'messages',
icon: () => h(ChatbubblesOutline),
href: '/messages',
})
options.push({
label: '',
key: 'collection',
icon: () => h(BookmarksOutline),
href: '/collection',
});
if (useFrindship) {
options.push({
label: '',
key: 'contacts',
icon: () => h(PeopleOutline),
href: '/contacts',
});
}
if (enableWallet) {
options.push({
label: '',
key: 'wallet',
icon: () => h(WalletOutline),
href: '/wallet',
});
}
options.push({
label: '',
key: 'setting',
icon: () => h(SettingsOutline),
href: '/setting',
});
return store.state.userInfo.id > 0
? options
: [
{
label: '广',
key: 'home',
icon: () => h(HomeOutline),
href: '/',
},
{
label: '',
key: 'topic',
icon: () => h(Hash),
href: '/topic',
},
];
});
const renderMenuLabel = (option: AnyObject) => {
if ('href' in option) {
return h('div', {}, option.label);
}
return option.label;
};
const renderMenuIcon = (option: AnyObject) => {
if (option.key === 'messages') {
return h(
NBadge,
{
dot: true,
show: hasUnreadMsg.value,
processing: true,
},
{
default: () =>
h(
NIcon,
{
color:
option.key === selectedPath.value
? 'var(--n-item-icon-color-active)'
: 'var(--n-item-icon-color)',
},
{ default: option.icon }
),
}
);
}
return h(NIcon, null, { default: option.icon });
};
const goRouter = (name: string, item: any = {}) => {
selectedPath.value = name;
router.push({
name, query: {
t: (new Date().getTime())
}
});
};
const goHome = () => {
if (route.path === '/') {
store.commit('refresh');
}
goRouter('home');
};
const triggerAuth = (key: string) => {
store.commit('triggerAuth', true);
store.commit('triggerAuthKey', key);
};
const handleLogout = () => {
store.commit('userLogout');
store.commit('refresh')
goHome()
};
window.$store = store;
window.$message = useMessage();
</script>
<style lang="less">
.sidebar-wrap::-webkit-scrollbar {
width: 0;
/* 隐藏滚动条的宽度 */
height: 0;
/* 隐藏滚动条的高度 */
}
.sidebar-wrap {
z-index: 99;
width: 200px;
height: 100vh;
position: fixed;
right: calc(50% + var(--content-main) / 2 + 10px);
padding: 12px 0;
box-sizing: border-box;
max-height: calc(100vh);
/* 调整高度 */
overflow: auto;
.n-menu .n-menu-item-content::before {
border-radius: 21px;
}
.logo-wrap {
display: flex;
justify-content: flex-start;
margin-bottom: 12px;
.logo-img {
margin-left: 24px;
&:hover {
cursor: pointer;
}
}
}
.user-wrap {
display: flex;
align-items: center;
position: absolute;
bottom: 12px;
left: 12px;
right: 12px;
.user-mini-wrap {
display: none;
}
.user-avatar {
margin-right: 8px;
}
.user-info {
display: flex;
flex-direction: column;
.nickname {
font-size: 16px;
font-weight: bold;
line-height: 16px;
height: 16px;
margin-bottom: 2px;
display: flex;
align-items: center;
.nickname-txt {
max-width: 90px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.logout {
margin-left: 6px;
}
}
.username {
font-size: 14px;
line-height: 16px;
height: 16px;
width: 120px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
opacity: 0.75;
}
}
.login-only-wrap {
display: flex;
justify-content: center;
width: 100%;
button {
margin: 0 4px;
width: 80%
}
}
.login-wrap {
display: flex;
justify-content: center;
width: 100%;
button {
margin: 0 4px;
}
}
}
}
.auth-card {
.n-card-header {
z-index: 999;
}
}
@media screen and (max-width: 821px) {
.sidebar-wrap {
width: 200px;
right: calc(100% - 200px);
}
.logo-wrap {
.logo-img {
margin-left: 12px !important;
}
}
.user-wrap {
.user-avatar,
.user-info,
.login-only-wrap,
.login-wrap {
margin-bottom: 32px;
}
// .user-mini-wrap {
// display: block !important;
// }
}
}</style>