refactor(health): consolidate monitor components

This commit is contained in:
AAEE86
2026-06-01 20:49:38 +08:00
parent d3c8317939
commit c1649fe837
14 changed files with 689 additions and 705 deletions
@@ -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>