Files
xh-medical-sign-web/clinical-web/src/components/layout/Header.vue
T

124 lines
2.8 KiB
Vue

<script setup lang="ts">
import { computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useAppStore } from '@/stores/app'
import { useLoginStore } from '@/stores/login'
const route = useRoute()
const appStore = useAppStore()
const loginStore = useLoginStore()
const currentResource = computed(() => loginStore.menuForPath(route.path))
const pageTitle = computed(() => currentResource.value?.name ?? String(route.meta.title ?? '首页'))
const pageGroup = computed(() => {
const directory = loginStore.authorization?.navigation.find((item) =>
item.children?.some((child) => child.id === currentResource.value?.id),
)
return directory?.name ?? String(route.meta.group ?? '工作台')
})
const selectedCampusId = computed<string>({
get: () => appStore.selectedCampusId,
set: (id) => appStore.selectCampus(id),
})
const campusPlaceholder = computed(() => {
if (appStore.campusLoading) {
return '院区加载中…'
}
return appStore.campusLoadFailed ? '院区加载失败' : '暂无可用院区'
})
onMounted(() => {
void appStore.loadCampuses()
})
</script>
<template>
<header class="clinical-header">
<div class="header-page">
<span class="header-title">{{ pageTitle }}</span>
<span class="header-breadcrumb">{{ pageGroup }} / {{ pageTitle }}</span>
</div>
<span class="header-spacer" />
<label class="campus-selector">
<span class="campus-label">院区</span>
<select
v-model="selectedCampusId"
:disabled="appStore.campusLoading || !appStore.campusRecords.length"
aria-label="选择院区"
>
<option v-if="!appStore.campusRecords.length" value="">
{{ campusPlaceholder }}
</option>
<option v-for="campus in appStore.campusRecords" :key="campus.id" :value="campus.id">
{{ campus.name }}
</option>
</select>
</label>
</header>
</template>
<style scoped>
.clinical-header {
display: flex;
flex-shrink: 0;
gap: 14px;
align-items: center;
height: var(--header-height);
padding: 0 20px;
background: #fff;
border-bottom: 1px solid var(--line);
}
.header-page {
display: flex;
gap: 14px;
align-items: baseline;
min-width: 0;
}
.header-title {
flex-shrink: 0;
color: var(--ink);
font-size: 16px;
font-weight: 700;
}
.header-breadcrumb {
overflow: hidden;
color: var(--mut);
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.header-spacer {
flex: 1;
}
.campus-selector {
display: flex;
flex-shrink: 0;
gap: 6px;
align-items: center;
}
.campus-label {
color: var(--mut);
font-size: 12px;
}
.campus-selector select {
width: auto;
padding: 4px 8px;
color: var(--brand-d);
font-size: 12.5px;
font-weight: 700;
background: var(--brand-l);
border: 1px solid var(--brand);
border-radius: 6px;
}
</style>