2025-11-03 10:20:30 +08:00

242 lines
6.7 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>
<a-layout-header class="basic-header" :class="cpClassNames" :style="cpStyles">
<!-- 左侧 -->
<div v-if="cpShowLeftSlot" class="basic-header__left">
<slot name="left"></slot>
</div>
<!-- 中间 -->
<div v-if="cpShowDefaultSlot" class="basic-header__center">
<slot></slot>
</div>
<!-- 右侧 -->
<div class="basic-header__right">
<a-space :size="16">
<a-tooltip title="居家服务数据大屏">
<action-button @click="handleBigScreen">
<BarChartOutlined />
</action-button>
</a-tooltip>
<action-button @click="handleConfig">
<setting-outlined></setting-outlined>
</action-button>
<a-dropdown :trigger="['hover']">
<action-button :style="{ height: '44px' }">
<translation-outlined />
</action-button>
<a-spin />
<template #overlay>
<a-menu v-model:selectedKeys="current">
<a-menu-item v-for="(item, key) in langData" :key="key" @click="handleLang(key)">
{{ item.icon }} {{ item.label }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<a-dropdown :trigger="['click']">
<action-button :style="{ height: '44px' }">
<a-avatar class="mr-8-1 display-inline-flex justify-content-center" :size="24"
:src="userInfo?.avatar">
</a-avatar>
<span>{{ userInfo?.name }}</span>
</action-button>
<a-spin />
<template #overlay>
<a-menu>
<!-- <a-menu-item key="edit" @click="handleOpen">
<edit-outlined />
{{ $t('component.RightContent.profile') }}
</a-menu-item> -->
<a-menu-item key="edit" @click="handleOpen">
<LeftOutlined />
返回平台
</a-menu-item>
<a-menu-item key="logout" @click="handleLogout">
<login-outlined></login-outlined>
{{ $t('component.RightContent.logout') }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-space>
</div>
</a-layout-header>
</template>
<script setup>
import { Modal } from 'ant-design-vue'
import { storeToRefs } from 'pinia'
import { computed, useSlots, ref } from 'vue'
import { useRouter } from 'vue-router'
import { LoginOutlined, SettingOutlined, EditOutlined, TranslationOutlined, BarChartOutlined, LeftOutlined } from '@ant-design/icons-vue'
import { useAppStore, useUserStore } from '@/store'
import ActionButton from './ActionButton.vue'
import { theme as antTheme } from 'ant-design-vue'
import { config as conf } from '@/config'
import { useI18n } from 'vue-i18n'
import storage from '@/utils/storage'
import useMultiTab from '@/store/modules/multiTab'
const { locale, t } = useI18n()
defineOptions({
name: 'BasicHeader',
})
/**
* @property {string} theme 主题【light=亮色dark=暗色】
*/
const props = defineProps({
theme: {
type: String,
},
})
const emit = defineEmits(['config'])
const slots = useSlots(['default', 'left', 'right'])
const userStore = useUserStore()
const appStore = useAppStore()
const router = useRouter()
const { config } = storeToRefs(appStore)
const { userInfo } = storeToRefs(userStore)
const { token } = antTheme.useToken()
const cpClassNames = computed(() => ({
[`basic-header--${props.theme}`]: true,
}))
const cpStyles = computed(() => {
const styles = {
zIndex: config.value.layout === 'topBottom' ? 120 : 110,
}
if (config.value.headerTheme === 'light') {
styles.boxShadow = `0 0 0 1px ${token.value.colorSplit}`
}
return styles
})
const cpShowLeftSlot = computed(() => !!slots.left)
const cpShowDefaultSlot = computed(() => !!slots.default)
const defaultLang = storage.local.getItem(conf('storage.lang')) || 'zh-ch'
const current = ref(defaultLang)
const langData = ref({
'zh-ch': {
lang: 'zh-ch',
label: '简体中文',
icon: '🇨🇳',
title: '语言',
},
'en-us': {
lang: 'en-us',
label: 'English',
icon: '🇺🇸',
title: 'Language',
},
})
/**
* 退出登录
*/
function handleLogout() {
Modal.confirm({
title: t('component.RightContent.logout'),
okText: t('button.confirm'),
cancelText: t('button.cancel'),
onOk: () => {
userStore.logout().then(() => {
router.push({
name: 'login',
})
})
},
})
}
/**
* 修改资料
*/
function handleOpen() {
storage.local.removeItem('platform')
storage.local.removeItem('stationId')
const multiTab = useMultiTab()
multiTab.$reset()
router.replace({ path: '/platForm' })
}
/**
* 切换语言
*/
function handleLang(lang) {
storage.local.setItem(conf('storage.lang'), lang)
locale.value = lang
current.value = lang
location.reload()
}
/**
* 配置
*/
function handleConfig() {
emit('config')
}
</script>
<style lang="less" scoped>
.basic-header {
height: v-bind('config.headerHeight + "px"');
line-height: 1;
position: sticky;
top: 0;
display: flex;
align-items: center;
padding-inline: 16px;
// box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
&__left {
flex-shrink: 0;
display: flex;
align-items: center;
}
&__center {
flex: auto;
min-width: 0;
}
&__right {
flex-shrink: 0;
margin: 0 0 0 auto;
display: flex;
align-items: center;
}
:deep(.ant-menu-horizontal) {
border: none;
line-height: v-bind('config.headerHeight + "px"');
}
&--light {
background: #fff;
}
&--dark {
color: #fff;
:deep(.action-btn) {
&:hover {
background: #252a3d;
}
}
}
:deep(.basic-menu) {
.basic-menu__title {
.ant-badge {
margin-top: -2px;
}
}
}
}
</style>