Files
system-monitor/backend/api/anomaly/chart.get.ts
2025-12-28 14:06:32 +09:00

81 lines
2.1 KiB
TypeScript

import { query } from '../../utils/db'
export default defineEventHandler(async (event) => {
const queryParams = getQuery(event)
const type = queryParams.type as string || 'short-term'
const period = queryParams.period as string || '24h'
// 기간/간격 계산
let interval = '24 hours'
let groupFormat = 'YYYY-MM-DD HH24:00'
if (period === '1h') {
interval = '1 hour'
groupFormat = 'YYYY-MM-DD HH24:MI'
} else if (period === '6h') {
interval = '6 hours'
groupFormat = 'YYYY-MM-DD HH24:00'
} else if (period === '12h') {
interval = '12 hours'
groupFormat = 'YYYY-MM-DD HH24:00'
} else if (period === '24h') {
interval = '24 hours'
groupFormat = 'YYYY-MM-DD HH24:00'
} else if (period === '7d') {
interval = '7 days'
groupFormat = 'YYYY-MM-DD'
} else if (period === '30d') {
interval = '30 days'
groupFormat = 'YYYY-MM-DD'
}
// 시간대별 집계 (anomaly_logs 테이블이 없으면 빈 배열 반환)
let rows: any[] = []
try {
rows = await query<any>(`
SELECT
to_char(detected_at, '${groupFormat}') as time_slot,
SUM(CASE WHEN level = 'warning' THEN 1 ELSE 0 END) as warning,
SUM(CASE WHEN level = 'danger' THEN 1 ELSE 0 END) as danger
FROM anomaly_logs
WHERE detect_type = $1
AND detected_at >= NOW() - INTERVAL '${interval}'
GROUP BY time_slot
ORDER BY time_slot ASC
`, [type])
} catch (e) {
// 테이블이 없으면 빈 배열
rows = []
}
// 시간 포맷 변환
const data = rows.map(r => ({
time: formatTimeLabel(r.time_slot, period),
warning: Number(r.warning),
danger: Number(r.danger)
}))
return {
data,
type,
period,
timestamp: new Date().toISOString()
}
})
function formatTimeLabel(timeSlot: string, period: string): string {
if (!timeSlot) return ''
if (period === '7d' || period === '30d') {
const parts = timeSlot.split('-')
return `${parts[1]}/${parts[2]}`
} else {
const parts = timeSlot.split(' ')
if (parts.length === 2) {
return parts[1].substring(0, 5)
}
return timeSlot.substring(11, 16)
}
}