287 lines
6.9 KiB
TypeScript
287 lines
6.9 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import axios from 'axios'
|
|
|
|
export interface Alert {
|
|
id: number
|
|
rule_name: string
|
|
message: string
|
|
level: 'critical' | 'error' | 'warning' | 'info'
|
|
alert_type: 'performance' | 'quality' | 'volume' | 'system' | 'business'
|
|
data?: any
|
|
created_at: string
|
|
resolved_at?: string
|
|
status: 'active' | 'resolved'
|
|
}
|
|
|
|
export interface AlertRule {
|
|
name: string
|
|
description?: string
|
|
alert_type: 'performance' | 'quality' | 'volume' | 'system' | 'business'
|
|
level: 'critical' | 'error' | 'warning' | 'info'
|
|
threshold: number
|
|
condition: string
|
|
enabled: boolean
|
|
check_interval: number
|
|
cooldown: number
|
|
}
|
|
|
|
export interface SystemHealth {
|
|
health_score: number
|
|
status: 'excellent' | 'good' | 'fair' | 'poor' | 'critical' | 'unknown'
|
|
details?: any
|
|
}
|
|
|
|
export interface MonitorStatus {
|
|
monitor_status: 'running' | 'stopped' | 'unknown'
|
|
}
|
|
|
|
export const useAlertStore = defineStore('alert', () => {
|
|
// 状态
|
|
const alerts = ref<Alert[]>([])
|
|
const rules = ref<AlertRule[]>([])
|
|
const health = ref<SystemHealth>({ health_score: 0, status: 'unknown' })
|
|
const monitorStatus = ref<MonitorStatus>({ monitor_status: 'unknown' })
|
|
const loading = ref(false)
|
|
const alertFilter = ref('all')
|
|
const alertSort = ref('time-desc')
|
|
|
|
// 计算属性
|
|
const filteredAlerts = computed(() => {
|
|
let filtered = alerts.value
|
|
|
|
// 应用过滤
|
|
if (alertFilter.value !== 'all') {
|
|
filtered = filtered.filter(alert => alert.level === alertFilter.value)
|
|
}
|
|
|
|
// 应用排序
|
|
filtered.sort((a, b) => {
|
|
switch (alertSort.value) {
|
|
case 'time-desc':
|
|
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
case 'time-asc':
|
|
return new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
case 'level-desc':
|
|
const levelOrder = { 'critical': 4, 'error': 3, 'warning': 2, 'info': 1 }
|
|
return (levelOrder[b.level] || 0) - (levelOrder[a.level] || 0)
|
|
case 'level-asc':
|
|
const levelOrderAsc = { 'critical': 4, 'error': 3, 'warning': 2, 'info': 1 }
|
|
return (levelOrderAsc[a.level] || 0) - (levelOrderAsc[b.level] || 0)
|
|
default:
|
|
return 0
|
|
}
|
|
})
|
|
|
|
return filtered
|
|
})
|
|
|
|
const alertStatistics = computed(() => {
|
|
const stats = alerts.value.reduce((acc, alert) => {
|
|
acc[alert.level] = (acc[alert.level] || 0) + 1
|
|
acc.total = (acc.total || 0) + 1
|
|
return acc
|
|
}, {} as Record<string, number>)
|
|
|
|
return {
|
|
critical: stats.critical || 0,
|
|
warning: stats.warning || 0,
|
|
info: stats.info || 0,
|
|
total: stats.total || 0
|
|
}
|
|
})
|
|
|
|
// 动作
|
|
const loadAlerts = async () => {
|
|
try {
|
|
loading.value = true
|
|
const response = await axios.get('/api/alerts')
|
|
alerts.value = response.data
|
|
} catch (error) {
|
|
console.error('加载预警失败:', error)
|
|
throw error
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const loadRules = async () => {
|
|
try {
|
|
loading.value = true
|
|
const response = await axios.get('/api/rules')
|
|
rules.value = response.data
|
|
} catch (error) {
|
|
console.error('加载规则失败:', error)
|
|
throw error
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const loadHealth = async () => {
|
|
try {
|
|
const response = await axios.get('/api/health')
|
|
health.value = response.data
|
|
} catch (error) {
|
|
console.error('加载健康状态失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const loadMonitorStatus = async () => {
|
|
try {
|
|
const response = await axios.get('/api/monitor/status')
|
|
monitorStatus.value = response.data
|
|
} catch (error) {
|
|
console.error('加载监控状态失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const startMonitoring = async () => {
|
|
try {
|
|
const response = await axios.post('/api/monitor/start')
|
|
if (response.data.success) {
|
|
await loadMonitorStatus()
|
|
return true
|
|
}
|
|
return false
|
|
} catch (error) {
|
|
console.error('启动监控失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const stopMonitoring = async () => {
|
|
try {
|
|
const response = await axios.post('/api/monitor/stop')
|
|
if (response.data.success) {
|
|
await loadMonitorStatus()
|
|
return true
|
|
}
|
|
return false
|
|
} catch (error) {
|
|
console.error('停止监控失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const checkAlerts = async () => {
|
|
try {
|
|
const response = await axios.post('/api/check-alerts')
|
|
if (response.data.success) {
|
|
await loadAlerts()
|
|
return response.data.count
|
|
}
|
|
return 0
|
|
} catch (error) {
|
|
console.error('检查预警失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const resolveAlert = async (alertId: number) => {
|
|
try {
|
|
const response = await axios.post(`/api/alerts/${alertId}/resolve`)
|
|
if (response.data.success) {
|
|
await loadAlerts()
|
|
return true
|
|
}
|
|
return false
|
|
} catch (error) {
|
|
console.error('解决预警失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const createRule = async (rule: Omit<AlertRule, 'name'> & { name: string }) => {
|
|
try {
|
|
const response = await axios.post('/api/rules', rule)
|
|
if (response.data.success) {
|
|
await loadRules()
|
|
return true
|
|
}
|
|
return false
|
|
} catch (error) {
|
|
console.error('创建规则失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const updateRule = async (originalName: string, rule: AlertRule) => {
|
|
try {
|
|
const response = await axios.put(`/api/rules/${originalName}`, rule)
|
|
if (response.data.success) {
|
|
await loadRules()
|
|
return true
|
|
}
|
|
return false
|
|
} catch (error) {
|
|
console.error('更新规则失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const deleteRule = async (ruleName: string) => {
|
|
try {
|
|
const response = await axios.delete(`/api/rules/${ruleName}`)
|
|
if (response.data.success) {
|
|
await loadRules()
|
|
return true
|
|
}
|
|
return false
|
|
} catch (error) {
|
|
console.error('删除规则失败:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const setAlertFilter = (filter: string) => {
|
|
alertFilter.value = filter
|
|
}
|
|
|
|
const setAlertSort = (sort: string) => {
|
|
alertSort.value = sort
|
|
}
|
|
|
|
const loadInitialData = async () => {
|
|
await Promise.all([
|
|
loadHealth(),
|
|
loadAlerts(),
|
|
loadRules(),
|
|
loadMonitorStatus()
|
|
])
|
|
}
|
|
|
|
return {
|
|
// 状态
|
|
alerts,
|
|
rules,
|
|
health,
|
|
monitorStatus,
|
|
loading,
|
|
alertFilter,
|
|
alertSort,
|
|
|
|
// 计算属性
|
|
filteredAlerts,
|
|
alertStatistics,
|
|
|
|
// 动作
|
|
loadAlerts,
|
|
loadRules,
|
|
loadHealth,
|
|
loadMonitorStatus,
|
|
startMonitoring,
|
|
stopMonitoring,
|
|
checkAlerts,
|
|
resolveAlert,
|
|
createRule,
|
|
updateRule,
|
|
deleteRule,
|
|
setAlertFilter,
|
|
setAlertSort,
|
|
loadInitialData
|
|
}
|
|
})
|