Files
Situation-Awareness-Platfor…/src/components/NavTabs/index.vue
2025-03-12 18:41:20 +08:00

350 lines
9.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-if="update" class="bar-right relative">
<div class="absolute right-0">
<d-menu v-if="mListMore.length === 0" width="100%" class="py-0 px-0 h-[47px]" mode="horizontal"
:disable-overflow-style="false" :default-select-keys="[id]" @select="handleNav">
<template v-for="item in menuList" :key="item.id">
<d-menu-item v-if="item.label !== '社区'" :key="item.id" class="g-menu-item"
:class="{ 'devui-menu-item-select': pType === item.id }">
<GLink :href="getLink(item)" :to="getTo(item)" class="flex gap-2 items-center">
<GIcon v-if="(pType === item.id) && item.activeIcon" :name="item.activeIcon" />
<GIcon :name="item.icon" v-else-if="item.icon" />
<span class="hover:text-light">{{ item.label }}</span>
<span v-if="item.num" class="hover:text-light"><Number :number="item.num" /></span>
</GLink>
</d-menu-item>
</template>
</d-menu>
<template v-else>
<d-menu width="100%" class="py-0 px-0 h-[47px]" mode="horizontal" :default-select-keys="[id]" @select="handleNav">
<template v-for="item in mList" :key="item.id">
<d-menu-item v-if="item.label !== '社区'" :key="item.id" class="g-menu-item"
:class="{ 'devui-menu-item-select': pType === item.id }">
<GLink :href="getLink(item)" :to="getTo(item)" class="flex gap-2 items-center">
<GIcon v-if="(pType === item.id) && item.activeIcon" :name="item.activeIcon" />
<GIcon :name="item.icon" v-else-if="item.icon" />
<span class="hover:text-light">{{ item.label }}</span>
<span v-if="item.num" class="hover:text-light"><Number :number="item.num" /></span>
</GLink>
</d-menu-item>
</template>
<d-sub-menu title="..." key="systemMore" class="d_menu_more">
<template v-for="item in mListMore" :key="item.id">
<d-menu-item v-if="item.label !== '社区'" :key="item.id" class="g-menu-item"
:class="{ 'devui-menu-item-select': pType === item.id }">
<div class="flex item_div">
<GLink :href="getLink(item)" :to="getTo(item)" class="flex gap-2 items-center">
<GIcon :name="item.icon" v-if="item.icon" />
<span class="hover:text-light">{{ item.label }}</span>
<span v-if="item.num" class="hover:text-light"><Number :number="item.num" /></span>
</GLink>
</div>
</d-menu-item>
</template>
</d-sub-menu>
</d-menu>
</template>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { orgInfoStore } from '@/stores/Org';
import { useGlobalInfoStore } from '@/stores/Global';
import { storeToRefs } from 'pinia';
import { useRepoId } from '@/utils/hooks/useRepoId';
const globalInfoStore = useGlobalInfoStore();
const orgStore = orgInfoStore();
interface Props {
filter?: Function | null;
}
const props = defineProps<Props>();
const route = useRoute();
const router = useRouter();
const update = ref<boolean>(true);
const id = ref('');
const pType = computed(() => route.meta.pType); // 页面归属的tab高亮
const { menuInfo, customMenuInfo } = storeToRefs(globalInfoStore);
const menuList = computed(() => {
let list: any;
if (globalInfoStore.menuType === 'org') {
list = [...menuInfo.value, ...customMenuInfo.value];
} else {
list = [...menuInfo.value];
}
// 菜单过滤
if (props.filter) {
list = list.filter(props.filter);
}
// 自定义菜单排序
if (customMenuInfo.value?.length) {
const index = list.findIndex((item) => item.id === 'orgSetting');
if (index >= 0) {
const orgSetting = list.splice(index, 1);
list.push(orgSetting[0]);
}
}
return list;
});
const mList = ref<any>([]);
const mListMore = ref<any>([]);
let seTime: any;
const computeW = () => {
if (seTime) clearTimeout(seTime);
seTime = setTimeout(() => {
mList.value = [];
mListMore.value = [];
nextTick(() => {
// 获取div元素的引用
const d1: any = document.querySelector('.bar-right');
const d2: any = document.querySelector('.devui-menu');
if (!d1.clientWidth) return;
let w = 0;
for (let i = 0; i < d2.children.length - 1; i++) {
w = w + d2.children[i].clientWidth + 32;
if (w < d1.clientWidth - 85) {
mList.value.push(menuList.value[i]);
} else {
mListMore.value.push(menuList.value[i]);
}
}
});
}, 100);
};
const { repoId } = useRepoId();
watch(
[repoId],
() => {
globalInfoStore.setMenuType(route?.meta?.type);
id.value = route.name as string;
update.value = false; // 需要强制刷新 疑似devui Bug
nextTick(() => {
update.value = true;
computeW();
});
},
{ immediate: true, deep: true }
);
watch(props, (val) => {
// listen to filter function changes
if (val.filter) {
update.value = false;
nextTick(() => {
update.value = true;
computeW();
});
}
});
watch(
() => menuList.value,
() => {
computeW();
},
{ immediate: true, deep: true }
);
// 点击tab跳转路由
const handleNav = (val: any) => {
if (/^\/organization/.test(val.key)) {
// 社区相关路由
const openUrl = val.key.replace(':namespace', orgStore.orgInfo.full_path);
window.open(openUrl, '_self');
}
};
const getTo = (data: any) => {
const link = {
href: data.link || (data.content || ''), // 如有传入了链接,使用链接打开,此时新页面会全量加载
to: null // 未传入链接基于router-link打开此时路由切换走spa router局部加载
};
if (!link.href) {
try {
link.to = router.resolve({
name: data.id,
params: {
...route.params
}
}).fullPath;
} catch (err) {
// ignore
}
}
return link.to ? link.to : null;
};
const getLink = (data: any) => {
return data.link || data.content || null;
};
const init = () => {
computeW();
window.addEventListener('resize', computeW);
};
onMounted(() => {
init();
});
onUnmounted(() => {
window.removeEventListener('resize', computeW);
if (seTime) clearTimeout(seTime);
});
</script>
<style lang="scss" scoped>
.lidiv {
line-height: var(--devui-line-height-base, 1.5);
display: inline-flex;
align-items: center;
transform: translateY(-2.5px);
text-align: center;
white-space: nowrap;
}
:deep(.devui-submenu-title-content::after) {
content: '更多';
font-weight: 400;
color: var(--color-light);
margin-left: 0.5rem;
}
:deep.devui-menu-horizontal {
.devui-menu-item {
padding: 0 !important;
margin: 0 16px;
}
}
:deep .devui-menu-item-horizontal-wrapper-show {
top: 40px !important;
left: -55% !important;
box-shadow: 0px 4px 8px 0px rgba(148, 163, 184, 0.1);
border-radius: 3px !important;
border: 1px solid #e6e7e8;
padding: 0 !important;
.devui-menu-item {
line-height: 24px !important;
margin: 16px 16px !important;
}
}
:deep .devui-menu-item-horizontal-wrapper-hidden {
top: 40px !important;
left: -55% !important;
box-shadow: 0px 4px 8px 0px rgba(148, 163, 184, 0.1);
border-radius: 3px;
border: 1px solid #e6e7e8;
.devui-menu-item {
line-height: 24px !important;
margin: 16px 16px !important;
}
}
:deep(.devui-submenu-title) {
line-height: 46px !important;
padding: 0 16px !important;
}
:deep(.devui-menu-item) {
line-height: 46px !important;
}
:deep(.devui-menu-item-select) {
span,
svg {
color: var(--color-font) !important;
font-weight: 600 !important;
}
}
:deep(.devui-menu-horizontal .devui-submenu div.devui-submenu-title .icon-chevron-up,
.devui-menu-horizontal .devui-submenu div.devui-submenu-title .icon-chevron-right) {
display: none;
}
:deep(.devui-menu-horizontal .devui-menu-item:after) {
left: 0;
width: 100%;
}
ul.g-menu {
padding: 0;
background-color: transparent;
height: 49px;
overflow-x: auto;
.g-menu-item {
line-height: 45px;
padding: 0 16px !important;
&:after {
left: 16px;
right: 16px;
}
&:last-of-type {
padding-right: 0 !important;
&::after {
right: 0;
}
}
}
:deep(.devui-menu-overflow-container) {
&:after {
left: 16px;
right: 16px;
}
}
.g-menu-item1 {
pointer-events: none;
}
:deep(.devui-menu-item-select) {
span,
svg {
color: var(--color-font) !important;
font-weight: 600 !important;
}
}
:deep(.devui-submenu) {
line-height: 36px;
}
}
.item_div{
a {
display: inline-block; /* 使 span 元素能够设置宽度 */
width: 106px; /* 设置 span 元素的宽度 */
overflow: hidden; /* 隐藏溢出内容 */
white-space: nowrap; /* 防止文本换行 */
text-overflow: ellipsis; /* 使用省略号来代表被省略的文本 */
span{
margin-left: 8px;
}
}
}
</style>
<style>
@media screen and (max-width: 1000px) {
.g-header .devui-menu-horizontal .devui-menu-item:hover:after {
width: 0;
}
}
</style>