feat: offline status
This commit is contained in:
parent
6d7d6cde37
commit
044a4b56e2
4
auto-imports.d.ts
vendored
4
auto-imports.d.ts
vendored
@ -34,6 +34,7 @@ declare global {
|
|||||||
const defineComponent: typeof import('vue')['defineComponent']
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
const defineLoader: typeof import('vue-router/auto')['defineLoader']
|
const defineLoader: typeof import('vue-router/auto')['defineLoader']
|
||||||
const definePage: typeof import('unplugin-vue-router/runtime')['definePage']
|
const definePage: typeof import('unplugin-vue-router/runtime')['definePage']
|
||||||
|
const doCheckOnline: typeof import('./src/composables/fetch')['doCheckOnline']
|
||||||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||||
@ -132,6 +133,7 @@ declare global {
|
|||||||
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
|
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
|
||||||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
|
const useBackendOnline: typeof import('./src/composables/fetch')['useBackendOnline']
|
||||||
const useBase64: typeof import('@vueuse/core')['useBase64']
|
const useBase64: typeof import('@vueuse/core')['useBase64']
|
||||||
const useBattery: typeof import('@vueuse/core')['useBattery']
|
const useBattery: typeof import('@vueuse/core')['useBattery']
|
||||||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
||||||
@ -334,6 +336,7 @@ declare module 'vue' {
|
|||||||
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
|
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
|
||||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||||
|
readonly doCheckOnline: UnwrapRef<typeof import('./src/composables/fetch')['doCheckOnline']>
|
||||||
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
|
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
|
||||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||||
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
|
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
|
||||||
@ -432,6 +435,7 @@ declare module 'vue' {
|
|||||||
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']>
|
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']>
|
||||||
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']>
|
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']>
|
||||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||||
|
readonly useBackendOnline: UnwrapRef<typeof import('./src/composables/fetch')['useBackendOnline']>
|
||||||
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
|
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
|
||||||
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
|
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
|
||||||
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
|
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
|
||||||
|
|||||||
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -56,6 +56,7 @@ declare module 'vue' {
|
|||||||
CollapsibleTrigger: typeof import('./src/components/ui/collapsible/CollapsibleTrigger.vue')['default']
|
CollapsibleTrigger: typeof import('./src/components/ui/collapsible/CollapsibleTrigger.vue')['default']
|
||||||
Day_cycle_power_wave_plot: typeof import('./src/components/dense/saber/day_cycle_power_wave_plot.vue')['default']
|
Day_cycle_power_wave_plot: typeof import('./src/components/dense/saber/day_cycle_power_wave_plot.vue')['default']
|
||||||
Day_fft_ifft_plot: typeof import('./src/components/dense/saber/day_fft_ifft_plot.vue')['default']
|
Day_fft_ifft_plot: typeof import('./src/components/dense/saber/day_fft_ifft_plot.vue')['default']
|
||||||
|
DefaultLayout: typeof import('./src/components/DefaultLayout.vue')['default']
|
||||||
DenseFramework: typeof import('./src/components/DenseFramework.vue')['default']
|
DenseFramework: typeof import('./src/components/DenseFramework.vue')['default']
|
||||||
Drawer: typeof import('./src/components/ui/drawer/Drawer.vue')['default']
|
Drawer: typeof import('./src/components/ui/drawer/Drawer.vue')['default']
|
||||||
DrawerContent: typeof import('./src/components/ui/drawer/DrawerContent.vue')['default']
|
DrawerContent: typeof import('./src/components/ui/drawer/DrawerContent.vue')['default']
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<meta name="description" content="Opinionated Vite Starter Template" />
|
<meta name="description" content="Opinionated Vite Starter Template" />
|
||||||
</head>
|
</head>
|
||||||
<body class="font-sans dark:text-white dark:bg-hex-121212">
|
<body class="font-sans dark:text-white dark:bg-hex-121212">
|
||||||
<div id="app"></div>
|
<div id="app" class="w-full h-full"></div>
|
||||||
<noscript>
|
<noscript>
|
||||||
<div>Please enable JavaScript to use this application.</div>
|
<div>Please enable JavaScript to use this application.</div>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"packageManager": "pnpm@9.14.4",
|
"packageManager": "pnpm@9.14.4",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"dev": "vite --port 3333 --open",
|
"dev": "vite --port 10514 --open",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"typecheck": "vue-tsc --noEmit",
|
"typecheck": "vue-tsc --noEmit",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
|
|||||||
301
src/App.vue
301
src/App.vue
@ -1,295 +1,22 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Icon } from '@iconify/vue'
|
import { useBackendOnline } from './composables'
|
||||||
|
|
||||||
import { ChevronRight, ChevronsUpDown } from 'lucide-vue-next'
|
const online = useBackendOnline()
|
||||||
import {
|
|
||||||
Breadcrumb,
|
|
||||||
BreadcrumbItem,
|
|
||||||
BreadcrumbLink,
|
|
||||||
BreadcrumbList,
|
|
||||||
BreadcrumbPage,
|
|
||||||
BreadcrumbSeparator,
|
|
||||||
} from '~/components/ui/breadcrumb'
|
|
||||||
|
|
||||||
import {
|
|
||||||
Collapsible,
|
|
||||||
CollapsibleContent,
|
|
||||||
CollapsibleTrigger,
|
|
||||||
} from '~/components/ui/collapsible'
|
|
||||||
import { Separator } from '~/components/ui/separator'
|
|
||||||
|
|
||||||
import {
|
|
||||||
Sidebar,
|
|
||||||
SidebarContent,
|
|
||||||
SidebarFooter,
|
|
||||||
SidebarGroup,
|
|
||||||
SidebarGroupLabel,
|
|
||||||
SidebarInset,
|
|
||||||
SidebarMenu,
|
|
||||||
SidebarMenuButton,
|
|
||||||
SidebarMenuItem,
|
|
||||||
SidebarMenuSub,
|
|
||||||
SidebarMenuSubButton,
|
|
||||||
SidebarMenuSubItem,
|
|
||||||
SidebarProvider,
|
|
||||||
SidebarRail,
|
|
||||||
} from '~/components/ui/sidebar'
|
|
||||||
import { authCode } from './composables'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
function logout() {
|
|
||||||
localStorage.clear()
|
|
||||||
sessionStorage.clear()
|
|
||||||
authCode.value = ''
|
|
||||||
router.push('/auth')
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!authCode.value) {
|
|
||||||
router.push('/auth')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// This is sample data.
|
|
||||||
const data = {
|
|
||||||
user: {
|
|
||||||
name: 'shadcn',
|
|
||||||
email: 'm@example.com',
|
|
||||||
avatar: '/avatars/shadcn.jpg',
|
|
||||||
},
|
|
||||||
navMain: [
|
|
||||||
{
|
|
||||||
title: '流星雷达',
|
|
||||||
url: '#',
|
|
||||||
icon: 'ri-radar-fill',
|
|
||||||
isActive: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: '潮汐波提取',
|
|
||||||
url: '/radar/TW-single',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '潮汐波统计',
|
|
||||||
url: '/radar/TW-stats',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '行星波提取',
|
|
||||||
url: '/radar/PW-single',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '行星波统计',
|
|
||||||
url: '/radar/PW-stats',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'SABER',
|
|
||||||
url: '#',
|
|
||||||
icon: 'game-icons:cracked-saber',
|
|
||||||
isActive: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: '重力波提取',
|
|
||||||
url: '/saber/gw/single',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '重力波统计',
|
|
||||||
url: '/saber/gw/stats',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '探空气球',
|
|
||||||
url: '#',
|
|
||||||
icon: 'bxs:balloon',
|
|
||||||
isActive: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: '重力波单次',
|
|
||||||
url: '/balloon/single',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '重力波统计',
|
|
||||||
url: '/balloon/year',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'TIDI',
|
|
||||||
url: '#',
|
|
||||||
icon: 'mdi:telescope',
|
|
||||||
isActive: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: '行星波振幅',
|
|
||||||
url: '/tidi/waves',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '行星波月统计',
|
|
||||||
url: '/tidi/month_stats',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'COSMIC',
|
|
||||||
url: '#',
|
|
||||||
icon: 'mdi:telescope',
|
|
||||||
isActive: true,
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: '行星波月统计',
|
|
||||||
url: '/cosmic/stats',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '行星波单次',
|
|
||||||
url: '/cosmic/single',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
关于: [
|
|
||||||
{
|
|
||||||
name: 'Design Engineering',
|
|
||||||
url: '#',
|
|
||||||
icon: 'Frame',
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
} as const
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div h-full w-full>
|
||||||
<div v-if="$route.path === '/auth'">
|
<div v-if="!online.isOnline.value" class="absolute z-1000000 h-full w-full bg-gray/4 backdrop-blur-md">
|
||||||
<RouterView />
|
<div class="h-full w-full flex flex-col items-center justify-center gap-3">
|
||||||
</div>
|
<h1 class="flex flex-row items-center gap-3 text-3xl">
|
||||||
<div v-else>
|
<div class="i-tabler-network" />
|
||||||
<SidebarProvider>
|
后端服务不在线
|
||||||
<Sidebar collapsible="icon">
|
</h1>
|
||||||
<SidebarHeader>
|
<div>
|
||||||
<Alert>
|
请检查后端是否运行, 或者服务器是否在维护
|
||||||
<AlertTitle>服务状态正常</AlertTitle>
|
</div>
|
||||||
</Alert>
|
</div>
|
||||||
</SidebarHeader>
|
|
||||||
<SidebarContent>
|
|
||||||
<SidebarGroup>
|
|
||||||
<SidebarGroupLabel>模型</SidebarGroupLabel>
|
|
||||||
<SidebarMenu>
|
|
||||||
<Collapsible
|
|
||||||
v-for="item in data.navMain"
|
|
||||||
:key="item.title"
|
|
||||||
as-child
|
|
||||||
:default-open="item.isActive"
|
|
||||||
class="group/collapsible"
|
|
||||||
>
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<CollapsibleTrigger as-child>
|
|
||||||
<SidebarMenuButton :tooltip="item.title">
|
|
||||||
<Icon :icon="item.icon" />
|
|
||||||
<span>{{ item.title }}</span>
|
|
||||||
<ChevronRight class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</CollapsibleTrigger>
|
|
||||||
|
|
||||||
<CollapsibleContent>
|
|
||||||
<SidebarMenuSub>
|
|
||||||
<SidebarMenuSubItem
|
|
||||||
v-for="subItem in item.items"
|
|
||||||
:key="subItem.title"
|
|
||||||
class="hover:bg-gray-100"
|
|
||||||
>
|
|
||||||
<SidebarMenuSubButton as-child>
|
|
||||||
<RouterLink
|
|
||||||
:to="subItem.url"
|
|
||||||
active-class="bg-accent-foreground text-accent"
|
|
||||||
>
|
|
||||||
<span> </span>
|
|
||||||
<span>{{ subItem.title }}</span>
|
|
||||||
</RouterLink>
|
|
||||||
</SidebarMenuSubButton>
|
|
||||||
</SidebarMenuSubItem>
|
|
||||||
</SidebarMenuSub>
|
|
||||||
</CollapsibleContent>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</Collapsible>
|
|
||||||
</SidebarMenu>
|
|
||||||
</SidebarGroup>
|
|
||||||
</SidebarContent>
|
|
||||||
<SidebarFooter>
|
|
||||||
<SidebarMenu>
|
|
||||||
<SidebarMenuItem flex="~ row items-center gap-2">
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger as-child>
|
|
||||||
<SidebarMenuButton
|
|
||||||
size="lg"
|
|
||||||
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
||||||
>
|
|
||||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
|
||||||
<span class="truncate font-semibold">操作员</span>
|
|
||||||
<span class="truncate text-xs">已授权</span>
|
|
||||||
</div>
|
|
||||||
<ChevronsUpDown class="ml-auto size-4" />
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent
|
|
||||||
class="min-w-56 w-[--radix-dropdown-menu-trigger-width] rounded-lg" side="bottom" align="end"
|
|
||||||
:side-offset="4"
|
|
||||||
>
|
|
||||||
<div @click="logout">
|
|
||||||
<DropdownMenuItem>
|
|
||||||
<Icon icon="heroicons-solid:logout" class="h-4 w-4" />
|
|
||||||
退出系统
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</div>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
<Button variant="outline" size="icon" class="ml-auto h-8 w-8">
|
|
||||||
<Icon icon="icon-park-outline:setting" class="h-4 w-4" />
|
|
||||||
<span class="sr-only">设置</span>
|
|
||||||
</Button>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</SidebarMenu>
|
|
||||||
</SidebarFooter>
|
|
||||||
<SidebarRail />
|
|
||||||
</Sidebar>
|
|
||||||
<SidebarInset>
|
|
||||||
<header class="group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 h-16 flex shrink-0 items-center justify-between gap-2 transition-[width,height] ease-linear">
|
|
||||||
<div class="flex items-center gap-2 px-4">
|
|
||||||
<Icon icon="heroicons-solid:home" class="h-4 w-4" />
|
|
||||||
<Separator orientation="vertical" class="mr-2 h-4" />
|
|
||||||
<Breadcrumb>
|
|
||||||
<BreadcrumbList>
|
|
||||||
<BreadcrumbItem>
|
|
||||||
<BreadcrumbLink href="/">
|
|
||||||
中高层大气波动解析识别技术系统
|
|
||||||
</BreadcrumbLink>
|
|
||||||
</BreadcrumbItem>
|
|
||||||
<BreadcrumbSeparator class="hidden md:block" />
|
|
||||||
|
|
||||||
<BreadcrumbItem class="hidden md:block">
|
|
||||||
<BreadcrumbLink href="#">
|
|
||||||
{{ $route.meta.group }}
|
|
||||||
</BreadcrumbLink>
|
|
||||||
</BreadcrumbItem>
|
|
||||||
<BreadcrumbSeparator class="hidden md:block" />
|
|
||||||
<BreadcrumbItem>
|
|
||||||
<BreadcrumbPage>{{ $route.meta.item_name }}</BreadcrumbPage>
|
|
||||||
</BreadcrumbItem>
|
|
||||||
</BreadcrumbList>
|
|
||||||
</Breadcrumb>
|
|
||||||
</div>
|
|
||||||
<div px-7>
|
|
||||||
<Alert variant="default">
|
|
||||||
<Icon icon="el:ok-circle" class="h-4 w-4 text-green!" />
|
|
||||||
<AlertTitle>服务状态正常</AlertTitle>
|
|
||||||
</Alert>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<RouterView class="h-full overflow-hidden" />
|
|
||||||
</SidebarInset>
|
|
||||||
</SidebarProvider>
|
|
||||||
</div>
|
</div>
|
||||||
|
<DefaultLayout />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
108
src/CONSTANT.ts
108
src/CONSTANT.ts
@ -2,3 +2,111 @@ const KURONEKO_API = 'http://100.89.232.74:18200'
|
|||||||
// export const API_BASE_URL = 'http://localhost:5000'
|
// export const API_BASE_URL = 'http://localhost:5000'
|
||||||
export const API_BASE_URL = import.meta.env.PROD ? 'https://gca-api.dustella.net:8443' : KURONEKO_API
|
export const API_BASE_URL = import.meta.env.PROD ? 'https://gca-api.dustella.net:8443' : KURONEKO_API
|
||||||
// export const API_BASE_URL = 'https://gca-api.dustella.net:8443'
|
// export const API_BASE_URL = 'https://gca-api.dustella.net:8443'
|
||||||
|
|
||||||
|
export const headerData = {
|
||||||
|
user: {
|
||||||
|
name: 'shadcn',
|
||||||
|
email: 'm@example.com',
|
||||||
|
avatar: '/avatars/shadcn.jpg',
|
||||||
|
},
|
||||||
|
navMain: [
|
||||||
|
{
|
||||||
|
title: '流星雷达',
|
||||||
|
url: '#',
|
||||||
|
icon: 'ri-radar-fill',
|
||||||
|
isActive: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: '潮汐波提取',
|
||||||
|
url: '/radar/TW-single',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '潮汐波统计',
|
||||||
|
url: '/radar/TW-stats',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '行星波提取',
|
||||||
|
url: '/radar/PW-single',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '行星波统计',
|
||||||
|
url: '/radar/PW-stats',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'SABER',
|
||||||
|
url: '#',
|
||||||
|
icon: 'game-icons:cracked-saber',
|
||||||
|
isActive: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: '重力波提取',
|
||||||
|
url: '/saber/gw/single',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '重力波统计',
|
||||||
|
url: '/saber/gw/stats',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '探空气球',
|
||||||
|
url: '#',
|
||||||
|
icon: 'bxs:balloon',
|
||||||
|
isActive: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: '重力波单次',
|
||||||
|
url: '/balloon/single',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '重力波统计',
|
||||||
|
url: '/balloon/year',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'TIDI',
|
||||||
|
url: '#',
|
||||||
|
icon: 'mdi:telescope',
|
||||||
|
isActive: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: '行星波振幅',
|
||||||
|
url: '/tidi/waves',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '行星波月统计',
|
||||||
|
url: '/tidi/month_stats',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'COSMIC',
|
||||||
|
url: '#',
|
||||||
|
icon: 'mdi:telescope',
|
||||||
|
isActive: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: '行星波月统计',
|
||||||
|
url: '/cosmic/stats',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '行星波单次',
|
||||||
|
url: '/cosmic/single',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
关于: [
|
||||||
|
{
|
||||||
|
name: 'Design Engineering',
|
||||||
|
url: '#',
|
||||||
|
icon: 'Frame',
|
||||||
|
},
|
||||||
|
|
||||||
|
],
|
||||||
|
} as const
|
||||||
|
|||||||
190
src/components/DefaultLayout.vue
Normal file
190
src/components/DefaultLayout.vue
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Icon } from '@iconify/vue'
|
||||||
|
|
||||||
|
import { ChevronRight, ChevronsUpDown } from 'lucide-vue-next'
|
||||||
|
import {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbItem,
|
||||||
|
BreadcrumbLink,
|
||||||
|
BreadcrumbList,
|
||||||
|
BreadcrumbPage,
|
||||||
|
BreadcrumbSeparator,
|
||||||
|
} from '~/components/ui/breadcrumb'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Collapsible,
|
||||||
|
CollapsibleContent,
|
||||||
|
CollapsibleTrigger,
|
||||||
|
} from '~/components/ui/collapsible'
|
||||||
|
import { Separator } from '~/components/ui/separator'
|
||||||
|
import {
|
||||||
|
Sidebar,
|
||||||
|
SidebarContent,
|
||||||
|
SidebarFooter,
|
||||||
|
SidebarGroup,
|
||||||
|
SidebarGroupLabel,
|
||||||
|
SidebarInset,
|
||||||
|
SidebarMenu,
|
||||||
|
SidebarMenuButton,
|
||||||
|
SidebarMenuItem,
|
||||||
|
SidebarMenuSub,
|
||||||
|
SidebarMenuSubButton,
|
||||||
|
SidebarMenuSubItem,
|
||||||
|
SidebarProvider,
|
||||||
|
SidebarRail,
|
||||||
|
} from '~/components/ui/sidebar'
|
||||||
|
|
||||||
|
import { authCode, useBackendOnline } from '../composables'
|
||||||
|
import { headerData as data } from '../CONSTANT'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
localStorage.clear()
|
||||||
|
sessionStorage.clear()
|
||||||
|
authCode.value = ''
|
||||||
|
router.push('/auth')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!authCode.value) {
|
||||||
|
router.push('/auth')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const online = useBackendOnline()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="$route.path === '/auth'">
|
||||||
|
<RouterView />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<SidebarProvider>
|
||||||
|
<Sidebar collapsible="icon">
|
||||||
|
<SidebarHeader>
|
||||||
|
<Alert>
|
||||||
|
<AlertTitle>服务状态正常 {{ online.isOnline }}</AlertTitle>
|
||||||
|
</Alert>
|
||||||
|
</SidebarHeader>
|
||||||
|
<SidebarContent>
|
||||||
|
<SidebarGroup>
|
||||||
|
<SidebarGroupLabel>模型</SidebarGroupLabel>
|
||||||
|
<SidebarMenu>
|
||||||
|
<Collapsible
|
||||||
|
v-for="item in data.navMain"
|
||||||
|
:key="item.title"
|
||||||
|
as-child
|
||||||
|
:default-open="item.isActive"
|
||||||
|
class="group/collapsible"
|
||||||
|
>
|
||||||
|
<SidebarMenuItem>
|
||||||
|
<CollapsibleTrigger as-child>
|
||||||
|
<SidebarMenuButton :tooltip="item.title">
|
||||||
|
<Icon :icon="item.icon" />
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
<ChevronRight class="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
|
||||||
|
<CollapsibleContent>
|
||||||
|
<SidebarMenuSub>
|
||||||
|
<SidebarMenuSubItem
|
||||||
|
v-for="subItem in item.items"
|
||||||
|
:key="subItem.title"
|
||||||
|
class="hover:bg-gray-100"
|
||||||
|
>
|
||||||
|
<SidebarMenuSubButton as-child>
|
||||||
|
<RouterLink
|
||||||
|
:to="subItem.url"
|
||||||
|
active-class="bg-accent-foreground text-accent"
|
||||||
|
>
|
||||||
|
<span> </span>
|
||||||
|
<span>{{ subItem.title }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</SidebarMenuSubButton>
|
||||||
|
</SidebarMenuSubItem>
|
||||||
|
</SidebarMenuSub>
|
||||||
|
</CollapsibleContent>
|
||||||
|
</SidebarMenuItem>
|
||||||
|
</Collapsible>
|
||||||
|
</SidebarMenu>
|
||||||
|
</SidebarGroup>
|
||||||
|
</SidebarContent>
|
||||||
|
<SidebarFooter>
|
||||||
|
<SidebarMenu>
|
||||||
|
<SidebarMenuItem flex="~ row items-center gap-2">
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger as-child>
|
||||||
|
<SidebarMenuButton
|
||||||
|
size="lg"
|
||||||
|
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
||||||
|
>
|
||||||
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||||
|
<span class="truncate font-semibold">操作员</span>
|
||||||
|
<span class="truncate text-xs">已授权</span>
|
||||||
|
</div>
|
||||||
|
<ChevronsUpDown class="ml-auto size-4" />
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent
|
||||||
|
class="min-w-56 w-[--radix-dropdown-menu-trigger-width] rounded-lg" side="bottom" align="end"
|
||||||
|
:side-offset="4"
|
||||||
|
>
|
||||||
|
<div @click="logout">
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<Icon icon="heroicons-solid:logout" class="h-4 w-4" />
|
||||||
|
退出系统
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
<Button variant="outline" size="icon" class="ml-auto h-8 w-8">
|
||||||
|
<Icon icon="icon-park-outline:setting" class="h-4 w-4" />
|
||||||
|
<span class="sr-only">设置</span>
|
||||||
|
</Button>
|
||||||
|
</SidebarMenuItem>
|
||||||
|
</SidebarMenu>
|
||||||
|
</SidebarFooter>
|
||||||
|
<SidebarRail />
|
||||||
|
</Sidebar>
|
||||||
|
<SidebarInset>
|
||||||
|
<header class="group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 h-16 flex shrink-0 items-center justify-between gap-2 transition-[width,height] ease-linear">
|
||||||
|
<div class="flex items-center gap-2 px-4">
|
||||||
|
<Icon icon="heroicons-solid:home" class="h-4 w-4" />
|
||||||
|
<Separator orientation="vertical" class="mr-2 h-4" />
|
||||||
|
<Breadcrumb>
|
||||||
|
<BreadcrumbList>
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink href="/">
|
||||||
|
中高层大气波动解析识别技术系统
|
||||||
|
</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator class="hidden md:block" />
|
||||||
|
|
||||||
|
<BreadcrumbItem class="hidden md:block">
|
||||||
|
<BreadcrumbLink href="#">
|
||||||
|
{{ $route.meta.group }}
|
||||||
|
</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator class="hidden md:block" />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbPage>{{ $route.meta.item_name }}</BreadcrumbPage>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</BreadcrumbList>
|
||||||
|
</Breadcrumb>
|
||||||
|
</div>
|
||||||
|
<div px-7>
|
||||||
|
<Alert variant="default">
|
||||||
|
<Icon icon="el:ok-circle" class="h-4 w-4 text-green!" />
|
||||||
|
<AlertTitle>服务状态正常</AlertTitle>
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<RouterView class="h-full overflow-hidden" />
|
||||||
|
</SidebarInset>
|
||||||
|
</SidebarProvider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -11,10 +11,9 @@ export const baseFetch = createFetch({
|
|||||||
baseUrl: API_BASE_URL,
|
baseUrl: API_BASE_URL,
|
||||||
options: {
|
options: {
|
||||||
async beforeFetch({ options }) {
|
async beforeFetch({ options }) {
|
||||||
const code = '0101'
|
|
||||||
options.headers = {
|
options.headers = {
|
||||||
...options.headers,
|
...options.headers,
|
||||||
Authorization: `${code}`,
|
Authorization: `${authCode.value}`,
|
||||||
}
|
}
|
||||||
return { options }
|
return { options }
|
||||||
},
|
},
|
||||||
@ -25,3 +24,51 @@ export const baseFetch = createFetch({
|
|||||||
},
|
},
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export async function doCheckOnline() {
|
||||||
|
let resp = null
|
||||||
|
try {
|
||||||
|
resp = await baseFetch('/ping', {
|
||||||
|
timeout: 2000,
|
||||||
|
})
|
||||||
|
const { error } = resp
|
||||||
|
if (error.value)
|
||||||
|
throw new Error(error.value)
|
||||||
|
const status = resp.response.value?.status
|
||||||
|
if (!status) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (status === 200) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else if (status >= 400 && status < 500) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (resp?.response.value?.status === 401) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
console.error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useBackendOnline = createSharedComposable(() => {
|
||||||
|
const isOnline = ref(true)
|
||||||
|
|
||||||
|
const useCheckInterval = useIntervalFn(() => {
|
||||||
|
doCheckOnline().then((online) => {
|
||||||
|
isOnline.value = online
|
||||||
|
})
|
||||||
|
}, 5000, {
|
||||||
|
immediate: true,
|
||||||
|
immediateCallback: true,
|
||||||
|
})
|
||||||
|
useCheckInterval.resume()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOnline,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user