mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-10 03:09:50 +08:00
refactor(health): consolidate monitor components
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="w-full space-y-1">
|
||||
<div class="flex h-6 w-full items-center gap-px">
|
||||
<TooltipProvider
|
||||
v-for="(segment, index) in segments"
|
||||
:key="index"
|
||||
:delay-duration="100"
|
||||
>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<div
|
||||
class="h-full flex-1 cursor-pointer rounded-sm transition-all duration-150 hover:scale-y-110 hover:brightness-110"
|
||||
:class="getTimelineColor(segment.status)"
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent
|
||||
side="top"
|
||||
:side-offset="8"
|
||||
class="max-w-xs"
|
||||
>
|
||||
<div class="text-xs whitespace-pre-line">
|
||||
{{ segment.tooltip }}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-[10px] text-muted-foreground">
|
||||
<span>{{ startLabel }}</span>
|
||||
<span>{{ endLabel }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import {
|
||||
formatTimestamp,
|
||||
getTimelineColor,
|
||||
getTimelineLabel
|
||||
} from './health-monitor-utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
timeline?: string[] | null
|
||||
timeRangeStart?: string | null
|
||||
timeRangeEnd?: string | null
|
||||
generatedAt?: string | null
|
||||
lookbackHours?: number
|
||||
fallbackSegments?: number
|
||||
entityLabel?: string
|
||||
entityName?: string | null
|
||||
}>(), {
|
||||
lookbackHours: 6,
|
||||
fallbackSegments: 60,
|
||||
entityLabel: '',
|
||||
entityName: null
|
||||
})
|
||||
|
||||
const statuses = computed(() => {
|
||||
if (Array.isArray(props.timeline) && props.timeline.length > 0) {
|
||||
return props.timeline
|
||||
}
|
||||
return Array.from({ length: props.fallbackSegments }, () => 'unknown')
|
||||
})
|
||||
|
||||
const startMs = computed(() => {
|
||||
const explicitStart = props.timeRangeStart
|
||||
? new Date(props.timeRangeStart).getTime()
|
||||
: NaN
|
||||
if (!Number.isNaN(explicitStart)) return explicitStart
|
||||
return endMs.value - props.lookbackHours * 60 * 60 * 1000
|
||||
})
|
||||
|
||||
const endMs = computed(() => {
|
||||
const explicitEnd = props.timeRangeEnd
|
||||
? new Date(props.timeRangeEnd).getTime()
|
||||
: NaN
|
||||
if (!Number.isNaN(explicitEnd)) return explicitEnd
|
||||
const generatedAt = props.generatedAt
|
||||
? new Date(props.generatedAt).getTime()
|
||||
: NaN
|
||||
if (!Number.isNaN(generatedAt)) return generatedAt
|
||||
return Date.now()
|
||||
})
|
||||
|
||||
const startLabel = computed(() => formatTimestamp(new Date(startMs.value).toISOString()))
|
||||
const endLabel = computed(() => formatTimestamp(new Date(endMs.value).toISOString()))
|
||||
|
||||
const segments = computed(() => {
|
||||
const segmentStatuses = statuses.value
|
||||
const safeRange = Math.max(endMs.value - startMs.value, 1)
|
||||
const interval = safeRange / segmentStatuses.length
|
||||
|
||||
return segmentStatuses.map((status, index) => {
|
||||
const cellStart = new Date(startMs.value + index * interval).toISOString()
|
||||
const cellEnd = new Date(startMs.value + (index + 1) * interval).toISOString()
|
||||
return {
|
||||
status,
|
||||
tooltip: buildTooltip(status, cellStart, cellEnd)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function buildTooltip(status: string, cellStart: string, cellEnd: string) {
|
||||
const entity = props.entityLabel && props.entityName
|
||||
? `\n${props.entityLabel}:${props.entityName}`
|
||||
: ''
|
||||
return `${formatTimestamp(cellStart)} - ${formatTimestamp(cellEnd)}${entity}\n状态:${getTimelineLabel(status)}`
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user