Files
hfb_sys/frontend/src/components/MobileBottomNav.vue
T
yml2213 d93795a4b4 统一订单列表混排租赁与撞车,后台撞车订单展示真实手机号
PC/移动端「我的订单」并行拉取两类订单并按时间混排展示;后台撞车订单买家手机号不再脱敏,便于履约联系。
2026-07-19 16:01:45 +08:00

142 lines
3.1 KiB
Vue

<script setup lang="ts">
import { useRoute, RouterLink } from 'vue-router'
import { useChatUnreadCount } from '@/features/chats/composables/useChatUnreadCount'
const route = useRoute()
const { unreadCount, unreadLabel } = useChatUnreadCount(route)
function isNavActive(path: string) {
if (path === '/m') return route.path === '/m'
// 订单 Tab 同时覆盖租赁订单与撞车订单路径
if (path === '/m/orders') {
return route.path.startsWith('/m/orders') || route.path.startsWith('/m/crash/orders')
}
return route.path.startsWith(path)
}
</script>
<template>
<nav class="bottom-nav">
<RouterLink to="/m" class="nav-item" :class="{ active: isNavActive('/m') }">
<van-icon name="home-o" :size="22" />
<span>首页</span>
</RouterLink>
<RouterLink to="/m/messages" class="nav-item" :class="{ active: isNavActive('/m/messages') }">
<span class="nav-icon-wrap">
<van-icon name="chat-o" :size="22" />
<em v-if="unreadCount > 0" class="nav-badge">{{ unreadLabel }}</em>
</span>
<span>消息</span>
</RouterLink>
<RouterLink to="/m/seller/listings/create" class="nav-item nav-publish">
<div class="publish-pill">+</div>
<span>发布</span>
</RouterLink>
<RouterLink to="/m/orders" class="nav-item" :class="{ active: isNavActive('/m/orders') }">
<van-icon name="orders-o" :size="22" />
<span>订单</span>
</RouterLink>
<RouterLink to="/m/profile" class="nav-item" :class="{ active: isNavActive('/m/profile') }">
<van-icon name="manager-o" :size="22" />
<span>我的</span>
</RouterLink>
</nav>
</template>
<style scoped>
.bottom-nav {
position: fixed;
left: 0;
right: 0;
bottom: -1px;
z-index: 100;
display: flex;
background: #fff;
border-top: 1px solid #eee;
padding-bottom: env(safe-area-inset-bottom);
height: calc(52px + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.bottom-nav::after {
position: absolute;
right: 0;
bottom: -18px;
left: 0;
height: 18px;
background: #fff;
content: '';
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
color: #999;
font-size: 10px;
text-decoration: none;
}
.nav-item.active {
color: #ff6a00;
}
.nav-item span {
font-weight: 600;
}
.nav-icon-wrap {
position: relative;
display: grid;
width: 24px;
height: 24px;
place-items: center;
}
.nav-badge {
position: absolute;
top: -5px;
right: -10px;
min-width: 16px;
height: 16px;
padding: 0 4px;
box-sizing: border-box;
border: 2px solid #fff;
border-radius: 999px;
background: #ef4444;
color: #fff;
font-size: 10px;
font-style: normal;
font-weight: 800;
line-height: 12px;
text-align: center;
}
.publish-pill {
width: 36px;
height: 26px;
display: grid;
place-items: center;
border-radius: 13px;
background: #ff6a00;
color: #fff;
font-size: 18px;
font-weight: 900;
}
.nav-publish span {
color: #ff6a00;
}
/* 响应式适配 */
@media (min-width: 520px) {
.bottom-nav {
left: calc((100vw - 430px) / 2);
right: calc((100vw - 430px) / 2);
}
}
</style>