76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
/**
|
|
* useSLAPrediction (#43) — SLA 위반 예측 훅
|
|
*
|
|
* GET /api/sla/prediction 으로 SLA 위반 위험이 있는 SR/서비스를 예측 조회.
|
|
* 폴링(기본 60초)으로 주기 갱신. 위험도(risk) 기준으로 정렬·요약 제공.
|
|
*/
|
|
import { useEffect, useState, useCallback, useRef } from 'react'
|
|
import { getSLAPrediction } from '../services/api'
|
|
|
|
export interface SLAPredictItem {
|
|
id: string | number
|
|
target_type: 'sr' | 'service'
|
|
target_name: string
|
|
sla_deadline: string // ISO
|
|
predicted_breach_at: string // ISO
|
|
risk: 'high' | 'medium' | 'low'
|
|
confidence: number // 0~1
|
|
remaining_minutes: number
|
|
}
|
|
|
|
interface SLAPredictResult {
|
|
items: SLAPredictItem[]
|
|
highRiskCount: number
|
|
loading: boolean
|
|
error: boolean
|
|
refresh: () => void
|
|
}
|
|
|
|
const RISK_ORDER: Record<string, number> = { high: 0, medium: 1, low: 2 }
|
|
|
|
export function useSLAPrediction(pollMs = 60000): SLAPredictResult {
|
|
const [items, setItems] = useState<SLAPredictItem[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState(false)
|
|
const timer = useRef<ReturnType<typeof setInterval> | null>(null)
|
|
|
|
const load = useCallback(async () => {
|
|
try {
|
|
const res = await getSLAPrediction()
|
|
const raw: any[] = res.data?.items ?? res.data?.predictions ?? res.data ?? []
|
|
const mapped: SLAPredictItem[] = raw.map((r: any) => ({
|
|
id: r.id ?? r.sr_id ?? r.target_id,
|
|
target_type: r.target_type ?? (r.sr_id ? 'sr' : 'service'),
|
|
target_name: r.target_name ?? r.title ?? r.service_name ?? `#${r.id ?? ''}`,
|
|
sla_deadline: r.sla_deadline ?? r.deadline ?? '',
|
|
predicted_breach_at: r.predicted_breach_at ?? r.eta ?? '',
|
|
risk: (r.risk ?? r.risk_level ?? 'low').toLowerCase(),
|
|
confidence: typeof r.confidence === 'number' ? r.confidence : 0,
|
|
remaining_minutes: r.remaining_minutes ?? r.remaining_min ?? 0,
|
|
}))
|
|
mapped.sort((a, b) =>
|
|
(RISK_ORDER[a.risk] ?? 9) - (RISK_ORDER[b.risk] ?? 9) ||
|
|
a.remaining_minutes - b.remaining_minutes
|
|
)
|
|
setItems(mapped)
|
|
setError(false)
|
|
} catch {
|
|
setError(true)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
load()
|
|
timer.current = setInterval(load, pollMs)
|
|
return () => { if (timer.current) clearInterval(timer.current) }
|
|
}, [load, pollMs])
|
|
|
|
const highRiskCount = items.filter(i => i.risk === 'high').length
|
|
|
|
return { items, highRiskCount, loading, error, refresh: load }
|
|
}
|
|
|
|
export default useSLAPrediction
|