Files
xh-medical-sign-web/clinical-web/src/layouts/ClinicalLayout.vue
T

108 lines
2.5 KiB
Vue

<script setup lang="ts">
import { onMounted, onUnmounted, watch } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import Container from '@/components/layout/Container.vue'
import Header from '@/components/layout/Header.vue'
import Menu from '@/components/layout/Menu.vue'
import { useLoginStore } from '@/stores/login'
const loginStore = useLoginStore()
const route = useRoute()
const router = useRouter()
let authorizationRefreshing = false
async function redirectIfUnauthorized() {
const resource = loginStore.menuForPath(route.path)
if (
route.name === 'menu-resource' &&
(!resource ||
resource.resourceType !== 'MENU' ||
resource.status !== 'ENABLED' ||
!resource.code ||
!loginStore.hasPermission(resource.code))
) {
await router.replace(loginStore.firstAuthorizedPath ?? '/forbidden')
}
}
async function refreshAuthorization() {
if (authorizationRefreshing) return
authorizationRefreshing = true
try {
await loginStore.refreshAuthorization()
await redirectIfUnauthorized()
} catch {
// A transient refresh error should not interrupt an otherwise active session.
} finally {
authorizationRefreshing = false
}
}
function handleWindowFocus() {
void refreshAuthorization()
}
/**
* 切标签页回来时浏览器不一定派发 window focus(窗口本身没失焦),
* 所以补一条 visibilitychange,保证「离开页面期间别人改了权限」能立刻收敛。
*/
function handleVisibilityChange() {
if (document.visibilityState === 'visible') {
void refreshAuthorization()
}
}
onMounted(() => {
window.addEventListener('focus', handleWindowFocus)
document.addEventListener('visibilitychange', handleVisibilityChange)
})
onUnmounted(() => {
window.removeEventListener('focus', handleWindowFocus)
document.removeEventListener('visibilitychange', handleVisibilityChange)
})
watch(
() => [route.path, loginStore.authorization] as const,
() => {
if (loginStore.authorization) {
void redirectIfUnauthorized()
}
},
)
</script>
<template>
<div class="clinical-layout">
<Menu />
<div class="clinical-main">
<Header />
<Container>
<RouterView />
</Container>
</div>
</div>
</template>
<style scoped>
.clinical-layout {
display: flex;
width: 100%;
height: 100vh;
min-height: 0;
overflow: hidden;
background: var(--bg);
}
.clinical-main {
display: flex;
flex: 1;
flex-direction: column;
min-width: 0;
min-height: 0;
height: 100%;
overflow: hidden;
}
</style>