admin-vue3/src/views/im/home/components/ToolBar.vue

111 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<!--
ToolBarIM 左侧工具栏
布局顶部头像 中间三 Tab消息/好友/群聊 底部设置
-->
<div class="flex flex-col items-center w-14 pt-4 pb-3 gap-2 flex-shrink-0 bg-[#2b2b2b]">
<!-- 顶部用户头像点击跳个人中心方块小圆角对齐 UserAvatar 风格 -->
<div class="mb-2 cursor-pointer" @click="goProfile">
<el-avatar :size="36" :src="avatar" shape="square" :style="{ borderRadius: '6px' }">
{{ nicknameShort }}
</el-avatar>
</div>
<!-- 中间三 Tab -->
<div class="flex flex-col items-center gap-2 flex-1 w-full">
<el-tooltip v-for="item in tabs" :key="item.name" :content="item.label" placement="right">
<div
class="flex items-center justify-center w-10 h-10 rounded-lg text-[#a0a0a0] cursor-pointer transition-all hover:text-white hover:bg-white/10"
:class="{ 'bg-white/15 text-white': isActive(item.name) }"
@click="goTab(item.name)"
>
<el-badge
v-if="item.name === 'ImHomeConversation' && totalUnread > 0"
:value="totalUnread"
:max="99"
class="tool-bar__badge"
>
<Icon :icon="item.icon" :size="22" />
</el-badge>
<Icon v-else :icon="item.icon" :size="22" />
</div>
</el-tooltip>
</div>
<!-- 底部设置按钮:点击跳个人中心 -->
<div class="flex flex-col items-center gap-2 w-full">
<el-tooltip content="设置" placement="right">
<div
class="flex items-center justify-center w-10 h-10 rounded-lg text-[#a0a0a0] cursor-pointer transition-all hover:text-white hover:bg-white/10"
@click="goProfile"
>
<el-icon :size="22"><Setting /></el-icon>
</div>
</el-tooltip>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Setting } from '@element-plus/icons-vue'
import Icon from '@/components/Icon/src/Icon.vue'
import { useUserStore } from '@/store/modules/user'
import { useConversationStore } from '../store/conversationStore'
defineOptions({ name: 'ImToolBar' })
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const conversationStore = useConversationStore()
/** 消息 Tab 的红点:所有非免打扰会话的未读总和 */
const totalUnread = computed(() => conversationStore.getTotalUnread)
/**
* 三个主 Tab 的配置name 对应路由 ImHomeConversation/Friend/Group
* 用 name 而非 pathpath 后期容易变前缀调整、嵌套加层name 更稳定
* icon 走通用 <Icon> 组件,支持 iconify 全部前缀ep: / ant-design: / svg-icon: 等)
* 群聊用 ant-design:team三人组合ep 没有"群体"图标,三人剪影跟 ep:user单人一眼区分单人 / 群体
*/
const tabs = [
{ name: 'ImHomeConversation', label: '消息', icon: 'ep:chat-dot-round' },
{ name: 'ImHomeFriend', label: '好友', icon: 'ep:user' },
{ name: 'ImHomeGroup', label: '群聊', icon: 'ant-design:team' }
]
/** 当前路由是否命中 Tab直接比对 route.name */
const isActive = (name: string) => route.name === name
const avatar = computed(() => userStore.getUser?.avatar || '')
/** 头像兜底:取昵称最后一个字符,避免空头像时的灰底过于突兀 */
const nicknameShort = computed(() => {
const name = userStore.getUser?.nickname || ''
return name ? name.slice(-1) : '我'
})
/** 切换 Tab当前 Tab 已选中时跳过,避免无意义的导航 */
const goTab = (name: string) => {
if (route.name === name) {
return
}
router.push({ name })
}
/** 跳转个人中心(路由 name=Profile */
const goProfile = () => router.push({ name: 'Profile' })
</script>
<style scoped>
/* el-badge 子组件内部类 UnoCSS 够不到,单独贴一条 :deep 覆盖 */
.tool-bar__badge :deep(.el-badge__content) {
top: 4px;
right: 8px;
border: none;
}
</style>