292 lines
7.5 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>
<div class="navbar" :class="'nav' + settingsStore.navType">
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container"
@toggleClick="toggleSideBar" />
<div class="app-name">
{{ yljgName }}
</div>
<div class="right-menu">
<div class="user-info" v-if="userStore.nickName">
欢迎,{{ userStore.nickName }}({{ userStore.roleName }})
</div>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-dropdown @command="handleCommand" class="avatar-container right-menu-item hover-effect" trigger="hover">
<div class="avatar-wrapper">
<img :src="userStore.avatar" class="user-avatar" />
</div>
<template #dropdown>
<el-dropdown-menu>
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
<span>布局设置</span>
</el-dropdown-item>
<el-dropdown-item divided command="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script setup lang="ts">
import { ElMessageBox } from 'element-plus'
import Breadcrumb from '@/components/Breadcrumb/index.vue'
import TopNav from '@/components/TopNav/index.vue'
import TopBar from './TopBar/index.vue'
import Logo from './Sidebar/Logo.vue'
import Hamburger from '@/components/Hamburger/index.vue'
import Screenfull from '@/components/Screenfull/index.vue'
import SizeSelect from '@/components/SizeSelect/index.vue'
import HeaderSearch from '@/components/HeaderSearch/index.vue'
import RuoYiGit from '@/components/RuoYi/Git/index.vue'
import RuoYiDoc from '@/components/RuoYi/Doc/index.vue'
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import { listhospital } from '@/api/regional/dict/hospital'
const appStore = useAppStore()
const userStore = useUserStore()
const settingsStore = useSettingsStore()
const yljgName = ref('区域检验平台')
function toggleSideBar(): void {
appStore.toggleSideBar()
}
function handleCommand(command: string): void {
switch (command) {
case "setLayout":
setLayout()
break
case "logout":
logout()
break
default:
break
}
}
function logout(): void {
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
userStore.logOut().then(() => {
location.href = '/index'
})
}).catch(() => { })
}
const emits = defineEmits(['setLayout'])
function setLayout(): void {
emits('setLayout')
}
async function toggleTheme(event?: MouseEvent): Promise<void> {
const x = event?.clientX || window.innerWidth / 2
const y = event?.clientY || window.innerHeight / 2
const wasDark = settingsStore.isDark
const isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches
const isSupported = typeof (document as any).startViewTransition === 'function' && !isReducedMotion
if (!isSupported) {
settingsStore.toggleTheme()
return
}
try {
const transition = document.startViewTransition(async () => {
await new Promise((resolve) => setTimeout(resolve, 10))
settingsStore.toggleTheme()
await nextTick()
})
await transition.ready
const endRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y))
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]
document.documentElement.animate(
{
clipPath: !wasDark ? [...clipPath].reverse() : clipPath
}, {
duration: 650,
easing: "cubic-bezier(0.4, 0, 0.2, 1)",
fill: "forwards",
pseudoElement: !wasDark ? "::view-transition-old(root)" : "::view-transition-new(root)"
}
)
await transition.finished
} catch (error) {
console.warn("View transition failed, falling back to immediate toggle:", error)
settingsStore.toggleTheme()
}
}
onMounted(() => {
listhospital({ pageSize: 100, pageNum: 1 }).then((resp: any) => {
yljgName.value = resp.rows.find((item: any) => item.hospitalId == userStore.sysLoginParam.loginYLJG)?.hospitalName || '区域检验平台'
})
})
</script>
<style lang='scss' scoped>
.navbar.nav3 {
.hamburger-container {
display: none !important;
}
}
.navbar {
height: 3.125rem;
/* 固定高度,与原有一致 */
overflow: hidden;
position: relative;
//background: #fff;
background: #304156;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.15);
//box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
display: flex;
/* 改为flex布局,确保子元素对齐 */
align-items: center;
/* 垂直居中 */
.hamburger-container {
line-height: 3.125rem;
/* 与导航栏高度一致 */
height: 100%;
padding: 0 1rem;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
/* 核心布局:产品名称 + 右侧内容容器 */
.custom-header-content {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1;
/* 占满剩余宽度 */
padding: 0 1.25rem;
height: 100%;
margin-left: .3125rem;
}
/* 产品名称样式 */
.app-name {
font-size: 1.125rem;
font-weight: 600;
color: #fff;
/* 若依主题色,可替换为品牌色 */
white-space: nowrap;
/* 防止换行 */
font-style: italic;
/* 关键:字体倾斜 */
/* 可选优化:增加倾斜角度控制(默认 italic 约 14 度,可自定义) */
/* transform: skewX(-10deg); /* 向左倾斜 10 度,正负值控制倾斜方向 */
}
.right-menu {
height: 100%;
line-height: 50px;
display: flex;
align-items: center;
margin-left: auto;
&:focus {
outline: none;
}
.user-info {
font-size: .875rem;
font-weight: 600;
display: flex;
align-items: center;
color: #e6f7f4;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
&.theme-switch-wrapper {
display: flex;
align-items: center;
svg {
transition: transform 0.3s;
&:hover {
transform: scale(1.15);
}
}
}
}
.avatar-container {
margin-right: 0px;
padding-right: 0px;
.avatar-wrapper {
margin-top: 10px;
right: 8px;
position: relative;
.user-avatar {
cursor: pointer;
width: 30px;
height: 30px;
margin-right: 8px;
border-radius: 50%;
}
.user-nickname {
position: relative;
left: 0px;
bottom: 10px;
font-size: 14px;
font-weight: bold;
}
i {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>