119 lines
2.8 KiB
Vue
119 lines
2.8 KiB
Vue
|
|
<script setup lang="ts">
|
|||
|
|
import { useRouter } from 'vue-router';
|
|||
|
|
|
|||
|
|
type LinkItem = {
|
|||
|
|
title: string;
|
|||
|
|
icon: string;
|
|||
|
|
to: { name: string };
|
|||
|
|
disabled?: boolean;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
type BlockItem = {
|
|||
|
|
id: string;
|
|||
|
|
title: string;
|
|||
|
|
list: any[];
|
|||
|
|
avatarRound: boolean;
|
|||
|
|
link: {
|
|||
|
|
to: {
|
|||
|
|
name: string;
|
|||
|
|
params: {
|
|||
|
|
namespace?: string;
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
defineProps<{
|
|||
|
|
linkList: LinkItem[];
|
|||
|
|
blockList: BlockItem[];
|
|||
|
|
}>();
|
|||
|
|
|
|||
|
|
const emit = defineEmits<{(event: 'handleToggle', value: boolean): void;
|
|||
|
|
}>();
|
|||
|
|
|
|||
|
|
const router = useRouter();
|
|||
|
|
// repo\org切换,强制页面重载
|
|||
|
|
const handleLinkClick = (event, data) => {
|
|||
|
|
const href = router.resolve(data.to).fullPath;
|
|||
|
|
window.open(href, '_self');
|
|||
|
|
emit('handleToggle', false);
|
|||
|
|
|
|||
|
|
event?.stopPropagation();
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<template>
|
|||
|
|
<div class="g-entrance-menu">
|
|||
|
|
<div class="g-entrance-menu-links">
|
|||
|
|
<OptionLink v-for="item in linkList" :key="item.title" v-bind="item">
|
|||
|
|
<GIcon :name="item.icon" />{{ item.title }}
|
|||
|
|
</OptionLink>
|
|||
|
|
</div>
|
|||
|
|
<div class="g-entrance-menu-block" v-for="block in blockList" :key="block.id">
|
|||
|
|
<div class="g-entrance-menu-block-title">
|
|||
|
|
<span>{{ block.title }}</span>
|
|||
|
|
<GLink v-bind="block.link">
|
|||
|
|
<GIcon name="gt-more-operate" />
|
|||
|
|
</GLink>
|
|||
|
|
</div>
|
|||
|
|
<div class="g-entrance-menu-block-list">
|
|||
|
|
<DataPanel :loading="block.loading" :empty="!block.list?.length" :card="false" skeleton>
|
|||
|
|
<OptionLink
|
|||
|
|
v-for="item in block.list"
|
|||
|
|
:key="item.name"
|
|||
|
|
v-bind="item"
|
|||
|
|
@click="handleLinkClick($event, item)"
|
|||
|
|
>
|
|||
|
|
<GAvatar
|
|||
|
|
:src="item.avatar"
|
|||
|
|
:name="item.avatarText"
|
|||
|
|
:width="16"
|
|||
|
|
:height="16"
|
|||
|
|
:is_round="block.avatarRound"
|
|||
|
|
></GAvatar>
|
|||
|
|
<d-tooltip :content="item.label" position="right" :mouse-enter-delay="800">
|
|||
|
|
<div class="ellipsis">{{ item.label }}</div>
|
|||
|
|
</d-tooltip>
|
|||
|
|
</OptionLink>
|
|||
|
|
<template #empty>
|
|||
|
|
<div class="py-2 flex-center opacity-50">暂无数据</div>
|
|||
|
|
</template>
|
|||
|
|
<template #loading>
|
|||
|
|
<d-skeleton :rows="5" />
|
|||
|
|
</template>
|
|||
|
|
</DataPanel>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<style scoped lang="scss">
|
|||
|
|
@import 'devui-theme/styles-var/devui-var.scss';
|
|||
|
|
|
|||
|
|
.g-entrance-menu {
|
|||
|
|
&-links {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
&-block {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
border-top: 1px solid var(--color-border-light);
|
|||
|
|
margin-top: 16px;
|
|||
|
|
&:last-child {
|
|||
|
|
padding-bottom: 0;
|
|||
|
|
}
|
|||
|
|
&-title {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #2d2d2e;
|
|||
|
|
line-height: 32px;
|
|||
|
|
margin-top: 8px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|