refactor: improve SSE connection handling and clean up notification component

This commit is contained in:
Jacky 2025-04-28 03:40:36 +00:00
parent 5aaf8cc36f
commit a39ec77992
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
6 changed files with 24 additions and 38 deletions

View file

@ -1,17 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Notification } from '@/api/notification' import type { Notification } from '@/api/notification'
import type { CustomRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer' import type { CustomRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import type { SSEvent } from 'sse.js'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import notificationApi from '@/api/notification' import notificationApi from '@/api/notification'
import { detailRender } from '@/components/Notification/detailRender' import { detailRender } from '@/components/Notification/detailRender'
import { useSSE } from '@/composables/useSSE'
import { NotificationTypeT } from '@/constants' import { NotificationTypeT } from '@/constants'
import { useUserStore } from '@/pinia' import { useUserStore } from '@/pinia'
import { BellOutlined, CheckCircleOutlined, CloseCircleOutlined, DeleteOutlined, InfoCircleOutlined, WarningOutlined } from '@ant-design/icons-vue' import { BellOutlined, CheckCircleOutlined, CloseCircleOutlined, DeleteOutlined, InfoCircleOutlined, WarningOutlined } from '@ant-design/icons-vue'
import { message, notification } from 'ant-design-vue' import { message, notification } from 'ant-design-vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { SSE } from 'sse.js'
import notifications from './notifications' import notifications from './notifications'
defineProps<{ defineProps<{
@ -22,32 +21,15 @@ dayjs.extend(relativeTime)
const loading = ref(false) const loading = ref(false)
const { token, unreadCount } = storeToRefs(useUserStore()) const { unreadCount } = storeToRefs(useUserStore())
const data = ref([]) as Ref<Notification[]> const data = ref([]) as Ref<Notification[]>
const sse = shallowRef(newSSE()) const { connect } = useSSE()
function reconnect() {
setTimeout(() => {
sse.value = newSSE()
}, 5000)
}
function newSSE() {
const s = new SSE('api/notifications/live', {
headers: {
Authorization: token.value,
},
})
s.onmessage = (e: SSEvent) => {
const data = JSON.parse(e.data)
// data.type may be 0
if (data.type === undefined || data.type === null || data.type === '') {
return
}
connect({
url: '/api/notifications/live',
onMessage: (data: Notification) => {
const typeTrans = { const typeTrans = {
0: 'error', 0: 'error',
1: 'warning', 1: 'warning',
@ -59,13 +41,8 @@ function newSSE() {
message: $gettext(data.title), message: $gettext(data.title),
description: detailRender({ text: data.details, record: data } as CustomRender), description: detailRender({ text: data.details, record: data } as CustomRender),
}) })
} },
})
// reconnect
s.onerror = reconnect
return s
}
function init() { function init() {
loading.value = true loading.value = true

View file

@ -6,7 +6,6 @@ import frontendTasks from './tasks/frontend'
export const useSelfCheckStore = defineStore('selfCheck', () => { export const useSelfCheckStore = defineStore('selfCheck', () => {
const data = ref<TaskReport[]>([]) const data = ref<TaskReport[]>([])
const requestError = ref(false)
const loading = ref(false) const loading = ref(false)
async function __check() { async function __check() {
@ -42,7 +41,6 @@ export const useSelfCheckStore = defineStore('selfCheck', () => {
} }
catch (error) { catch (error) {
console.error(error) console.error(error)
requestError.value = true
} }
finally { finally {
loading.value = false loading.value = false
@ -72,7 +70,7 @@ export const useSelfCheckStore = defineStore('selfCheck', () => {
} }
const hasError = computed(() => { const hasError = computed(() => {
return requestError.value || data.value?.some(item => item.status === ReportStatus.Error) return data.value?.some(item => item.status === ReportStatus.Error)
}) })
return { data, loading, fixing, hasError, check, fix } return { data, loading, fixing, hasError, check, fix }

View file

@ -25,7 +25,9 @@ export function useSSE() {
* Connect to SSE service * Connect to SSE service
*/ */
function connect(options: SSEOptions) { function connect(options: SSEOptions) {
disconnect() if (token.value) {
return
}
const { const {
url, url,

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import settings from '@/api/settings' import settings from '@/api/settings'
import PageHeader from '@/components/PageHeader/PageHeader.vue' import PageHeader from '@/components/PageHeader/PageHeader.vue'
import { useSettingsStore } from '@/pinia' import { useSettingsStore, useUserStore } from '@/pinia'
import { throttle } from 'lodash' import { throttle } from 'lodash'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import FooterLayout from './FooterLayout.vue' import FooterLayout from './FooterLayout.vue'
@ -44,10 +44,13 @@ settings.get_server_name().then(r => {
const breadList = ref([]) const breadList = ref([])
provide('breadList', breadList) provide('breadList', breadList)
const userStore = useUserStore()
const { token } = storeToRefs(userStore)
</script> </script>
<template> <template>
<ALayout class="full-screen-wrapper min-h-screen"> <ALayout :key="token" class="full-screen-wrapper min-h-screen">
<div class="drawer-sidebar"> <div class="drawer-sidebar">
<ADrawer <ADrawer
v-model:open="drawerVisible" v-model:open="drawerVisible"

View file

@ -131,7 +131,7 @@ export function setupResponseInterceptor() {
case 403: case 403:
user.logout() user.logout()
await router.push('/login') await router.push('/login')
break return
} }
} }

View file

@ -1,6 +1,7 @@
<script setup lang="tsx"> <script setup lang="tsx">
import cert from '@/api/cert' import cert from '@/api/cert'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue' import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import { useGlobalStore } from '@/pinia'
import { CloudUploadOutlined, SafetyCertificateOutlined } from '@ant-design/icons-vue' import { CloudUploadOutlined, SafetyCertificateOutlined } from '@ant-design/icons-vue'
import RemoveCert from '../components/RemoveCert.vue' import RemoveCert from '../components/RemoveCert.vue'
import WildcardCertificate from '../components/WildcardCertificate.vue' import WildcardCertificate from '../components/WildcardCertificate.vue'
@ -8,6 +9,10 @@ import certColumns from './certColumns'
const refWildcard = ref() const refWildcard = ref()
const refTable = ref() const refTable = ref()
const globalStore = useGlobalStore()
const { processingStatus } = storeToRefs(globalStore)
</script> </script>
<template> <template>
@ -25,6 +30,7 @@ const refTable = ref()
<AButton <AButton
type="link" type="link"
size="small" size="small"
:disabled="processingStatus.auto_cert_processing"
@click="() => refWildcard.open()" @click="() => refWildcard.open()"
> >
<SafetyCertificateOutlined /> <SafetyCertificateOutlined />