This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
<template>
|
||||
<div :class="layoutCls">
|
||||
<t-head-menu :class="menuCls" :theme="menuTheme" expand-type="popup" :value="active">
|
||||
<template #logo>
|
||||
<span v-if="showLogo" class="header-logo-container" @click="handleNav('/role-select')">
|
||||
<span class="header-brand">财务系统</span>
|
||||
</span>
|
||||
<div v-else class="header-operate-left">
|
||||
<span class="current-role">{{ user.roleName || '尚未选择身份' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="layout !== 'side'" #default>
|
||||
<menu-content class="header-menu" :nav-data="menu" />
|
||||
</template>
|
||||
<template #operations>
|
||||
<div class="operations-container">
|
||||
<t-dropdown :min-column-width="120" trigger="click">
|
||||
<template #dropdown>
|
||||
<t-dropdown-item class="operations-dropdown-container-item" @click="handleNav('/profile')">
|
||||
<user-circle-icon />{{ t('layout.header.user') }}
|
||||
</t-dropdown-item>
|
||||
<t-dropdown-item class="operations-dropdown-container-item" @click="handleLogout">
|
||||
<poweroff-icon />{{ t('layout.header.signOut') }}
|
||||
</t-dropdown-item>
|
||||
</template>
|
||||
<t-button class="header-user-btn" theme="default" variant="text">
|
||||
<template #icon>
|
||||
<t-icon class="header-user-avatar" name="user-circle" />
|
||||
</template>
|
||||
<div class="header-user-account">{{ user.displayName }}</div>
|
||||
<template #suffix><chevron-down-icon /></template>
|
||||
</t-button>
|
||||
</t-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</t-head-menu>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ChevronDownIcon, PoweroffIcon, UserCircleIcon } from 'tdesign-icons-vue-next';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { prefix } from '@/config/global';
|
||||
import { t } from '@/locales';
|
||||
import { getActive } from '@/router';
|
||||
import { usePermissionStore, useUserStore } from '@/store';
|
||||
import type { MenuRoute, ModeType } from '@/types/interface';
|
||||
|
||||
import MenuContent from './MenuContent.vue';
|
||||
|
||||
const { theme, layout, showLogo, menu, isFixed, isCompact } = defineProps({
|
||||
theme: {
|
||||
type: String,
|
||||
default: 'light',
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'top',
|
||||
},
|
||||
showLogo: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
menu: {
|
||||
type: Array as PropType<MenuRoute[]>,
|
||||
default: () => [],
|
||||
},
|
||||
isFixed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCompact: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxLevel: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const user = useUserStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
|
||||
const active = computed(() => getActive());
|
||||
|
||||
const layoutCls = computed(() => [`${prefix}-header-layout`]);
|
||||
|
||||
const menuCls = computed(() => {
|
||||
return [
|
||||
{
|
||||
[`${prefix}-header-menu`]: !isFixed,
|
||||
[`${prefix}-header-menu-fixed`]: isFixed,
|
||||
[`${prefix}-header-menu-fixed-side`]: layout === 'side' && isFixed,
|
||||
[`${prefix}-header-menu-fixed-side-compact`]: layout === 'side' && isFixed && isCompact,
|
||||
},
|
||||
];
|
||||
});
|
||||
const menuTheme = computed(() => theme as ModeType);
|
||||
|
||||
const handleNav = (url: string) => {
|
||||
router.push(url);
|
||||
};
|
||||
|
||||
const handleLogout = async () => {
|
||||
await user.logout();
|
||||
permissionStore.restoreRoutes();
|
||||
await router.replace('/login');
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.@{starter-prefix}-header {
|
||||
&-menu-fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 1001;
|
||||
|
||||
:deep(.t-head-menu__inner) {
|
||||
padding-right: var(--td-comp-margin-xl);
|
||||
}
|
||||
|
||||
&-side {
|
||||
left: 232px;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
width: auto;
|
||||
transition: all 0.3s;
|
||||
|
||||
&-compact {
|
||||
left: 64px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-logo-container {
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.header-menu {
|
||||
flex: 1 1 auto;
|
||||
display: inline-flex;
|
||||
|
||||
:deep(.t-menu__item) {
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.operations-container {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.t-popup__reference {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.t-button {
|
||||
margin-left: var(--td-comp-margin-l);
|
||||
}
|
||||
}
|
||||
|
||||
.header-operate-left {
|
||||
display: flex;
|
||||
align-items: normal;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.current-role {
|
||||
color: var(--td-text-color-secondary);
|
||||
font-size: 13px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.header-logo-container {
|
||||
width: 184px;
|
||||
height: 26px;
|
||||
display: flex;
|
||||
margin-left: 24px;
|
||||
color: var(--td-text-color-primary);
|
||||
|
||||
.t-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.header-user-account {
|
||||
min-width: 0;
|
||||
max-width: 160px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
color: var(--td-text-color-primary);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.header-brand {
|
||||
color: var(--td-brand-color);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media (width <= 640px) {
|
||||
.operations-container {
|
||||
max-width: calc(100vw - 96px);
|
||||
|
||||
.t-button {
|
||||
min-width: 0;
|
||||
margin-left: var(--td-comp-margin-s);
|
||||
}
|
||||
}
|
||||
|
||||
.header-user-account {
|
||||
max-width: 104px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.t-head-menu__inner) {
|
||||
border-bottom: 1px solid var(--td-component-stroke);
|
||||
}
|
||||
|
||||
.t-menu--light {
|
||||
.header-user-account {
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.t-menu--dark {
|
||||
.t-head-menu__inner {
|
||||
border-bottom: 1px solid var(--td-gray-color-10);
|
||||
}
|
||||
|
||||
.header-user-account {
|
||||
color: rgb(255 255 255 / 55%);
|
||||
}
|
||||
}
|
||||
|
||||
.operations-dropdown-container-item {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
:deep(.t-dropdown__item-text) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.t-icon {
|
||||
font-size: var(--td-comp-size-xxxs);
|
||||
margin-right: var(--td-comp-margin-s);
|
||||
}
|
||||
|
||||
:deep(.t-dropdown__item) {
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
:deep(.t-dropdown__item) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- eslint-disable-next-line vue-scoped-css/enforce-style-type -->
|
||||
<style lang="less">
|
||||
.operations-dropdown-container-item {
|
||||
.t-dropdown__item-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user