✨ feat(im): 优化 ToolBar.vue 组件

- tabs / goTab / goProfile 从 path 切到路由 name:path 后期容易随前缀调整变动,name 更稳定
- isActive 由 path 前缀比对简化为 route.name 全等比对(IM 三 Tab 无嵌套子路由,足够)
- 群聊图标 svg-icon:peoples → ant-design:team:三人组合跟 ep:user(单人)视觉区分更明显
- 给 goTab / goProfile 补 JSDoc;清理 5 个 TODO @AI
pull/881/head
YunaiV 2026-04-26 23:45:27 +08:00
parent 3a77001b42
commit 8790d6b128
1 changed files with 26 additions and 39 deletions

View File

@ -3,36 +3,24 @@
ToolBar:IM 左侧工具栏
布局:顶部头像 → 中间三 Tab(消息/好友/群聊)→ 底部设置
-->
<div
class="flex flex-col items-center w-14 pt-4 pb-3 gap-2 flex-shrink-0 bg-[#2b2b2b]"
>
<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' }"
>
<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.path"
:content="item.label"
placement="right"
>
<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.path) }"
@click="goTab(item.path)"
:class="{ 'bg-white/15 text-white': isActive(item.name) }"
@click="goTab(item.name)"
>
<el-badge
v-if="item.path === '/im/home/conversation' && totalUnread > 0"
v-if="item.name === 'ImHomeConversation' && totalUnread > 0"
:value="totalUnread"
:max="99"
class="tool-bar__badge"
@ -78,31 +66,19 @@ const conversationStore = useConversationStore()
const totalUnread = computed(() => conversationStore.getTotalUnread)
/**
* 三个主 Tab 的配置,路径对应 /im/home/{conversation,friend,group}
* icon 走通用 <Icon> 组件,支持 ep: / svg-icon: 前缀
* 群聊用项目自带的 svg-icon:peoples(双人剪影)一眼区分单人 / 群体
* 三个主 Tab 的配置,name 对应路由 ImHomeConversation/Friend/Group
* 用 name 而非 path:path 后期容易变(前缀调整、嵌套加层),name 更稳定
* icon 走通用 <Icon> 组件,支持 iconify 全部前缀(ep: / ant-design: / svg-icon: 等)
* 群聊用 ant-design:team(三人组合):ep 没有"群体"图标,三人剪影跟 ep:user(单人)一眼区分单人 / 群体
*/
// TODO @AI:改成 name 更合适把?
// TODO @AI: 其他地方,是不是也能减少 path?主要 path 容易变!
const tabs = [
{ path: '/im/home/conversation', label: '消息', icon: 'ep:chat-dot-round' },
{ path: '/im/home/friend', label: '好友', icon: 'ep:user' },
{ path: '/im/home/group', label: '群聊', icon: 'svg-icon:peoples' } // TODO @AI:这个图标不是很好,看看怎么优化下;ep 里,有 group 概念的图标么?
{ name: 'ImHomeConversation', label: '消息', icon: 'ep:chat-dot-round' },
{ name: 'ImHomeFriend', label: '好友', icon: 'ep:user' },
{ name: 'ImHomeGroup', label: '群聊', icon: 'ant-design:team' }
]
/** 当前路由是否命中 Tab:完全匹配或 Tab 路径是当前路径前缀均算命中 */
const isActive = (path: string) => route.path === path || route.path.startsWith(path + '/')
// TODO @AI:方法注释
const goTab = (path: string) => {
if (route.path === path) {
return
}
router.push(path)
}
// TODO @AI:改成 name 更合适把?
const goProfile = () => router.push('/user/profile')
/** 当前路由是否命中 Tab:直接比对 route.name */
const isActive = (name: string) => route.name === name
const avatar = computed(() => userStore.getUser?.avatar || '')
@ -111,6 +87,17 @@ 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>