290 lines
6.2 KiB
Vue
290 lines
6.2 KiB
Vue
<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(user.workbenchRoute)">
|
|
<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>
|