227 lines
7.4 KiB
Vue
227 lines
7.4 KiB
Vue
<script lang="ts">
|
|
function renderIcon(icon: Component): () => VNode {
|
|
return () => h(NIcon, null, { default: () => h(icon) });
|
|
}
|
|
</script>
|
|
|
|
<script setup lang="ts">
|
|
import { SettingsDrawer } from '@/components';
|
|
import { useStompClient } from '@/composables';
|
|
import { useLineStationsQuery } from '@/composables';
|
|
import { LINE_STATIONS_QUERY_KEY, LINE_DEVICES_QUERY_KEY, LINE_ALARMS_QUERY_KEY } from '@/constants';
|
|
import { useAlarmStore, useSettingStore, useUserStore } from '@/stores';
|
|
import { useIsFetching } from '@tanstack/vue-query';
|
|
import {
|
|
AlertFilled,
|
|
BugFilled,
|
|
CaretDownFilled,
|
|
DoubleLeftOutlined,
|
|
DoubleRightOutlined,
|
|
EnvironmentFilled,
|
|
/* AreaChartOutlined, */ FileTextFilled,
|
|
HddFilled,
|
|
LogoutOutlined,
|
|
SettingOutlined,
|
|
} from '@vicons/antd';
|
|
import type { AxiosError } from 'axios';
|
|
import { NBadge, NButton, NDropdown, NFlex, NIcon, NLayout, NLayoutContent, NLayoutFooter, NLayoutHeader, NLayoutSider, NMenu, NScrollbar, type DropdownOption, type MenuOption } from 'naive-ui';
|
|
import { storeToRefs } from 'pinia';
|
|
import { computed, h, onBeforeMount, ref, watch, type Component, type VNode } from 'vue';
|
|
import { RouterLink, useRoute, useRouter } from 'vue-router';
|
|
|
|
useStompClient();
|
|
|
|
const userStore = useUserStore();
|
|
const { userInfo } = storeToRefs(userStore);
|
|
|
|
const alarmStore = useAlarmStore();
|
|
const { unreadAlarmCount } = storeToRefs(alarmStore);
|
|
|
|
const settingStore = useSettingStore();
|
|
const { menuCollpased } = storeToRefs(settingStore);
|
|
|
|
const onToggleMenuCollapsed = () => {
|
|
menuCollpased.value = !menuCollpased.value;
|
|
};
|
|
|
|
const { error: stationListQueryError } = useLineStationsQuery();
|
|
|
|
watch(stationListQueryError, (newStationListQueryError) => {
|
|
if (newStationListQueryError) {
|
|
window.$message.error(newStationListQueryError.message);
|
|
}
|
|
});
|
|
|
|
const lineStationsFetchingCount = useIsFetching({ queryKey: [LINE_STATIONS_QUERY_KEY] });
|
|
const lineDevicesFetchingCount = useIsFetching({ queryKey: [LINE_DEVICES_QUERY_KEY] });
|
|
const lineAlarmsFetchingCount = useIsFetching({ queryKey: [LINE_ALARMS_QUERY_KEY] });
|
|
const fetchingCount = computed(() => {
|
|
return lineStationsFetchingCount.value + lineDevicesFetchingCount.value + lineAlarmsFetchingCount.value;
|
|
});
|
|
|
|
onBeforeMount(() => {
|
|
userStore.userGetInfo().catch((err) => window.$message.error((err as AxiosError).message));
|
|
});
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
|
|
const menuOptions = ref<MenuOption[]>([
|
|
{
|
|
label: () => h(RouterLink, { to: '/station' }, { default: () => '车站状态' }),
|
|
key: '/station',
|
|
icon: renderIcon(EnvironmentFilled),
|
|
},
|
|
{
|
|
label: () => h(RouterLink, { to: '/device' }, { default: () => '设备诊断' }),
|
|
key: '/device',
|
|
icon: renderIcon(HddFilled),
|
|
},
|
|
{
|
|
label: () => h(RouterLink, { to: '/alarm' }, { default: () => '设备告警' }),
|
|
key: '/alarm',
|
|
icon: renderIcon(AlertFilled),
|
|
},
|
|
// {
|
|
// label: () => h(RouterLink, { to: '/statistics' }, { default: () => '设备数据统计' }),
|
|
// key: '/statistics',
|
|
// icon: renderIcon(AreaChartOutlined),
|
|
// },
|
|
{
|
|
label: '系统日志',
|
|
key: '/log',
|
|
icon: renderIcon(FileTextFilled),
|
|
children: [
|
|
{
|
|
label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }),
|
|
key: '/log/vimp-log',
|
|
},
|
|
{
|
|
label: () => h(RouterLink, { to: '/log/call-log' }, { default: () => '上级调用日志' }),
|
|
key: '/log/call-log',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: () => h(RouterLink, { to: '/debug' }, { default: () => '调试' }),
|
|
key: '/debug',
|
|
icon: renderIcon(BugFilled),
|
|
show: import.meta.env.DEV,
|
|
},
|
|
]);
|
|
|
|
const dropdownOptions = ref<DropdownOption[]>([
|
|
{
|
|
label: '退出登录',
|
|
key: 'logout',
|
|
icon: renderIcon(LogoutOutlined),
|
|
onClick: async () => {
|
|
try {
|
|
await userStore.userLogout();
|
|
router.push('/login');
|
|
} catch (_) {
|
|
window.$message.error('退出登录失败');
|
|
}
|
|
},
|
|
},
|
|
]);
|
|
|
|
const selectDropdownOption = (key: string, option: DropdownOption) => {
|
|
if (typeof option['onClick'] === 'function') {
|
|
option['onClick']();
|
|
}
|
|
};
|
|
|
|
const routeToRoot = () => {
|
|
router.push('/');
|
|
};
|
|
|
|
const routeToAlarmPage = () => {
|
|
unreadAlarmCount.value = 0;
|
|
if (route.path !== '/alarm') {
|
|
router.push('/alarm');
|
|
}
|
|
};
|
|
|
|
const settingsDrawerShow = ref(false);
|
|
const openSettingsDrawer = () => {
|
|
settingsDrawerShow.value = true;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<NScrollbar x-scrollable style="width: 100vw; height: 100vh">
|
|
<NLayout has-sider :content-style="{ 'min-width': '1400px' }">
|
|
<NLayoutSider bordered :collapsed="menuCollpased" collapse-mode="width" :collapsed-width="64" @update:collapsed="onToggleMenuCollapsed">
|
|
<NFlex vertical justify="space-between" :size="0" style="height: 100%">
|
|
<NMenu :collapsed="menuCollpased" :collapsed-width="64" :collapsed-icon-size="20" :value="route.path" :options="menuOptions" />
|
|
<NButton block quaternary :focusable="false" @click="onToggleMenuCollapsed">
|
|
<template #icon>
|
|
<NIcon :component="menuCollpased ? DoubleRightOutlined : DoubleLeftOutlined" />
|
|
</template>
|
|
</NButton>
|
|
</NFlex>
|
|
</NLayoutSider>
|
|
<NLayout :native-scrollbar="false">
|
|
<NLayoutHeader bordered class="app-layout-header">
|
|
<NFlex justify="space-between" align="center" :size="8" style="width: 100%; height: 100%">
|
|
<NFlex>
|
|
<div style="font-size: 16px; font-weight: 500; margin-left: 16px; cursor: pointer" @click="routeToRoot">网络设备管理平台</div>
|
|
<NButton text size="tiny" :loading="fetchingCount > 0" />
|
|
</NFlex>
|
|
<NFlex align="center" :size="0" style="height: 100%">
|
|
<NDropdown trigger="hover" show-arrow :options="dropdownOptions" @select="selectDropdownOption">
|
|
<NButton :focusable="false" quaternary icon-placement="right" style="height: 100%">
|
|
<template #default>
|
|
<span>{{ userInfo?.nickName ?? '' }}</span>
|
|
</template>
|
|
<template #icon>
|
|
<NIcon :component="CaretDownFilled" />
|
|
</template>
|
|
</NButton>
|
|
</NDropdown>
|
|
<NButton :focusable="false" quaternary @click="openSettingsDrawer" style="height: 100%">
|
|
<template #icon>
|
|
<NIcon :component="SettingOutlined" />
|
|
</template>
|
|
</NButton>
|
|
</NFlex>
|
|
</NFlex>
|
|
</NLayoutHeader>
|
|
<NLayoutContent class="app-layout-content">
|
|
<RouterView />
|
|
</NLayoutContent>
|
|
<NLayoutFooter bordered class="app-layout-footer">
|
|
<NFlex :align="'center'" style="height: 100%; margin: 0 16px">
|
|
<NBadge :value="unreadAlarmCount">
|
|
<NButton secondary strong @click="routeToAlarmPage">
|
|
<template #icon>
|
|
<NIcon :component="AlertFilled" />
|
|
</template>
|
|
</NButton>
|
|
</NBadge>
|
|
</NFlex>
|
|
</NLayoutFooter>
|
|
</NLayout>
|
|
</NLayout>
|
|
</NScrollbar>
|
|
<SettingsDrawer v-model:show="settingsDrawerShow" />
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
$layout-header-height: 48px;
|
|
$layout-footer-height: 48px;
|
|
|
|
.app-layout-header {
|
|
height: $layout-header-height;
|
|
}
|
|
|
|
.app-layout-content {
|
|
height: calc(100vh - $layout-header-height - $layout-footer-height);
|
|
}
|
|
|
|
.app-layout-footer {
|
|
height: $layout-footer-height;
|
|
}
|
|
</style>
|