305 lines
8.7 KiB
Vue
305 lines
8.7 KiB
Vue
<template>
|
||
<div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }">
|
||
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
|
||
<div class="layout-navbars-breadcrumb-user-icon">
|
||
<i
|
||
class="iconfont"
|
||
:class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'"
|
||
:title="$t('user.title1')"
|
||
></i>
|
||
</div>
|
||
<template #dropdown>
|
||
<el-dropdown-menu>
|
||
<el-dropdown-item command="zh-cn" :disabled="state.disabledI18n === 'zh-cn'">简体中文</el-dropdown-item>
|
||
<el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</template>
|
||
</el-dropdown>
|
||
<div class="layout-navbars-breadcrumb-user-icon" @click="onLockClick">
|
||
<el-icon :title="$t('layout.threeLockScreenTime')">
|
||
<ele-Lock />
|
||
</el-icon>
|
||
</div>
|
||
<div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
|
||
<el-icon :title="$t('user.title2')">
|
||
<ele-Search />
|
||
</el-icon>
|
||
</div>
|
||
<div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
|
||
<i class="icon-skin iconfont" :title="$t('user.title3')"></i>
|
||
</div>
|
||
<div class="layout-navbars-breadcrumb-user-icon">
|
||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||
<template #reference>
|
||
<el-badge :is-dot="isDot">
|
||
<el-icon :title="$t('user.title4')">
|
||
<ele-Bell />
|
||
</el-icon>
|
||
</el-badge>
|
||
</template>
|
||
<template #default>
|
||
<UserNews ref="newsRef" />
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
<div class="layout-navbars-breadcrumb-user-icon">
|
||
<el-popover placement="bottom" trigger="click" :persistent="false">
|
||
<template #reference>
|
||
<el-icon><Phone /></el-icon>
|
||
</template>
|
||
<template #default>
|
||
<div>联系热线:</div>
|
||
<div>15657370065</div>
|
||
<div>18367908152</div>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
|
||
<i
|
||
class="iconfont"
|
||
:title="state.isScreenfull ? $t('user.title6') : $t('user.title5')"
|
||
:class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
|
||
></i>
|
||
</div>
|
||
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
|
||
<span class="layout-navbars-breadcrumb-user-link">
|
||
<img :src="$fileUrl(userInfos.user.avatar)" class="layout-navbars-breadcrumb-user-link-photo mr5" @error="$fileRetry(userInfos.user.avatar)" />
|
||
{{ userInfos.user.username }}
|
||
<el-icon class="el-icon--right">
|
||
<ele-ArrowDown />
|
||
</el-icon>
|
||
</span>
|
||
<template #dropdown>
|
||
<el-dropdown-menu>
|
||
<el-dropdown-item command="/home">{{ $t("user.dropdown1") }}</el-dropdown-item>
|
||
<el-dropdown-item command="personal">{{ $t("user.dropdown2") }}</el-dropdown-item>
|
||
<el-dropdown-item divided command="logOut">{{ $t("user.dropdown5") }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</template>
|
||
</el-dropdown>
|
||
<Search ref="searchRef" />
|
||
<global-websocket uri="/admin/ws/info" v-if="websocketEnable" @rollback="rollback" />
|
||
<personal-drawer ref="personalDrawerRef"></personal-drawer>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts" name="layoutBreadcrumbUser">
|
||
import { logout } from "/@/api/login"
|
||
import { ElMessage, ElMessageBox } from "element-plus"
|
||
import screenfull from "screenfull"
|
||
import { useI18n } from "vue-i18n"
|
||
import { useUserInfo } from "/@/stores/userInfo"
|
||
import { useThemeConfig } from "/@/stores/themeConfig"
|
||
import other from "/@/utils/other"
|
||
import mittBus from "/@/utils/mitt"
|
||
import { Local, Session } from "/@/utils/storage"
|
||
import { formatAxis } from "/@/utils/formatTime"
|
||
import { useMsg } from "/@/stores/msg"
|
||
import { fetchUserMessageList } from "/@/api/admin/message"
|
||
|
||
// 引入组件
|
||
const GlobalWebsocket = defineAsyncComponent(() => import("/@/components/Websocket/index.vue"))
|
||
const UserNews = defineAsyncComponent(() => import("/@/layout/navBars/breadcrumb/userNews.vue"))
|
||
const Search = defineAsyncComponent(() => import("/@/layout/navBars/breadcrumb/search.vue"))
|
||
const PersonalDrawer = defineAsyncComponent(() => import("/@/views/admin/system/user/personal.vue"))
|
||
|
||
// 定义变量内容
|
||
const { locale, t } = useI18n()
|
||
const router = useRouter()
|
||
const stores = useUserInfo()
|
||
const storesThemeConfig = useThemeConfig()
|
||
const { userInfos } = storeToRefs(stores)
|
||
const { themeConfig } = storeToRefs(storesThemeConfig)
|
||
const searchRef = ref()
|
||
const newsRef = ref()
|
||
const personalDrawerRef = ref()
|
||
|
||
interface State {
|
||
[key: string]: boolean | string
|
||
isScreenfull: boolean
|
||
disabledI18n: string
|
||
disabledSize: string
|
||
}
|
||
|
||
const state = reactive<State>({
|
||
isScreenfull: false,
|
||
disabledI18n: "zh-cn",
|
||
disabledSize: "large",
|
||
})
|
||
|
||
// 是否开启websocket
|
||
const websocketEnable = ref(import.meta.env.VITE_WEBSOCKET_ENABLE === "true")
|
||
|
||
// 设置分割样式
|
||
const layoutUserFlexNum = computed(() => {
|
||
let num: string | number = ""
|
||
const { layout, isClassicSplitMenu } = themeConfig.value
|
||
const layoutArr: string[] = ["defaults", "columns"]
|
||
if (layoutArr.includes(layout) || (layout === "classic" && !isClassicSplitMenu)) num = "1"
|
||
else num = ""
|
||
return num
|
||
})
|
||
// 全屏点击时
|
||
const onScreenfullClick = () => {
|
||
if (!screenfull.isEnabled) {
|
||
ElMessage.warning("暂不不支持全屏")
|
||
return false
|
||
}
|
||
screenfull.toggle()
|
||
screenfull.on("change", () => {
|
||
if (screenfull.isFullscreen) state.isScreenfull = true
|
||
else state.isScreenfull = false
|
||
})
|
||
}
|
||
// 布局配置 icon 点击时
|
||
const onLayoutSetingClick = () => {
|
||
mittBus.emit("openSetingsDrawer")
|
||
}
|
||
// 下拉菜单点击时
|
||
const onHandleCommandClick = (path: string) => {
|
||
if (path === "logOut") {
|
||
ElMessageBox({
|
||
closeOnClickModal: false,
|
||
closeOnPressEscape: false,
|
||
title: t("user.logOutTitle"),
|
||
message: t("user.logOutMessage"),
|
||
showCancelButton: true,
|
||
confirmButtonText: t("user.logOutConfirm"),
|
||
cancelButtonText: t("user.logOutCancel"),
|
||
buttonSize: "default",
|
||
beforeClose: (action, instance, done) => {
|
||
if (action === "confirm") {
|
||
instance.confirmButtonLoading = true
|
||
instance.confirmButtonText = t("user.logOutExit")
|
||
setTimeout(() => {
|
||
done()
|
||
setTimeout(() => {
|
||
instance.confirmButtonLoading = false
|
||
}, 300)
|
||
}, 700)
|
||
} else {
|
||
done()
|
||
}
|
||
},
|
||
})
|
||
.then(async () => {
|
||
// 关闭全部的标签页
|
||
mittBus.emit("onCurrentContextmenuClick", Object.assign({}, { contextMenuClickId: 3, ...router }))
|
||
// 调用后台接口
|
||
await logout()
|
||
// 清除缓存/token等
|
||
Session.clear()
|
||
// 使用 reload 时,不需要调用 resetRoute() 重置路由
|
||
window.location.reload()
|
||
})
|
||
.catch(() => {})
|
||
} else if (path === "personal") {
|
||
// 打开个人页面
|
||
personalDrawerRef.value.open()
|
||
} else {
|
||
router.push(path)
|
||
}
|
||
}
|
||
// 菜单搜索点击
|
||
const onSearchClick = () => {
|
||
searchRef.value.openSearch()
|
||
}
|
||
// 语言切换
|
||
const onLanguageChange = (lang: string) => {
|
||
Local.remove("themeConfig")
|
||
themeConfig.value.globalI18n = lang
|
||
Local.set("themeConfig", themeConfig.value)
|
||
locale.value = lang
|
||
other.useTitle()
|
||
initI18nOrSize("globalI18n", "disabledI18n")
|
||
}
|
||
// 锁屏
|
||
const onLockClick = () => {
|
||
themeConfig.value.isLockScreen = true
|
||
themeConfig.value.lockScreenTime = 0
|
||
Local.set("themeConfig", themeConfig.value)
|
||
}
|
||
|
||
// 初始化组件大小/i18n
|
||
const initI18nOrSize = (value: string, attr: string) => {
|
||
state[attr] = Local.get("themeConfig")[value]
|
||
}
|
||
|
||
// 获取到消息
|
||
const rollback = (msg: string) => {
|
||
useMsg().setMsg({ label: "websocket消息", value: msg, time: formatAxis(new Date()) })
|
||
}
|
||
|
||
// 获取是否显示未读
|
||
const isDot = ref(false)
|
||
const getIsDot = () => {
|
||
fetchUserMessageList({ category: "1", readFlag: "0" }).then((res) => {
|
||
isDot.value = res.data.total !== 0
|
||
})
|
||
}
|
||
// 页面加载时
|
||
onMounted(() => {
|
||
if (Local.get("themeConfig")) {
|
||
initI18nOrSize("globalComponentSize", "disabledSize")
|
||
initI18nOrSize("globalI18n", "disabledI18n")
|
||
}
|
||
|
||
getIsDot()
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.layout-navbars-breadcrumb-user {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
|
||
&-link {
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
white-space: nowrap;
|
||
|
||
&-photo {
|
||
width: 25px;
|
||
height: 25px;
|
||
border-radius: 100%;
|
||
}
|
||
}
|
||
|
||
&-icon {
|
||
padding: 0 10px;
|
||
cursor: pointer;
|
||
color: var(--next-bg-topBarColor);
|
||
height: 50px;
|
||
line-height: 50px;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
&:hover {
|
||
background: var(--next-color-user-hover);
|
||
|
||
i {
|
||
display: inline-block;
|
||
animation: logoAnimation 0.3s ease-in-out;
|
||
}
|
||
}
|
||
}
|
||
|
||
:deep(.el-dropdown) {
|
||
color: var(--next-bg-topBarColor);
|
||
}
|
||
|
||
:deep(.el-badge) {
|
||
height: 40px;
|
||
line-height: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
:deep(.el-badge__content.is-fixed) {
|
||
top: 12px;
|
||
}
|
||
}
|
||
</style>
|