Files
PingWatch/backend/app/api/alerts.py
T
v6ole 848f804169 PingWatch 网络设备离线监控系统
- FastAPI 后端 + Vue 3 前端
- Docker Compose 一键部署
- Casdoor OAuth 认证集成
- LogHive 集中式日志
- 设备批量 CSV 导入/导出
- WebSocket 实时状态推送
- 企业微信告警通知
- fping 高性能并发 Ping 检测

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 15:02:04 +08:00

134 lines
4.7 KiB
Python

"""告警记录 API"""
from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Query
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_db
from app.core.auth import get_current_user
from app.models.device import Device
from app.models.alert_event import AlertEvent, AlertTypeEnum
from app.models.user import User
from app.schemas.alert import AlertEventOut
router = APIRouter(prefix="/api/alerts", tags=["告警记录"])
@router.get("", response_model=dict)
async def list_alerts(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
device_id: Optional[int] = None,
alert_type: Optional[str] = None,
is_resolved: Optional[bool] = None,
start_time: Optional[datetime] = None,
end_time: Optional[datetime] = None,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""查询告警记录,支持分页和过滤"""
query = select(AlertEvent)
count_query = select(func.count(AlertEvent.id))
# 过滤条件
if device_id:
query = query.where(AlertEvent.device_id == device_id)
count_query = count_query.where(AlertEvent.device_id == device_id)
if alert_type:
query = query.where(AlertEvent.alert_type == alert_type)
count_query = count_query.where(AlertEvent.alert_type == alert_type)
if is_resolved is not None:
query = query.where(AlertEvent.is_resolved == is_resolved)
count_query = count_query.where(AlertEvent.is_resolved == is_resolved)
if start_time:
query = query.where(AlertEvent.created_at >= start_time)
count_query = count_query.where(AlertEvent.created_at >= start_time)
if end_time:
query = query.where(AlertEvent.created_at <= end_time)
count_query = count_query.where(AlertEvent.created_at <= end_time)
# 总数
total_result = await db.execute(count_query)
total = total_result.scalar() or 0
# 分页
offset = (page - 1) * page_size
query = query.order_by(AlertEvent.created_at.desc()).offset(offset).limit(page_size)
result = await db.execute(query)
events = list(result.scalars().all())
# 关联设备信息
device_ids = {e.device_id for e in events if e.device_id > 0}
devices_map = {}
if device_ids:
dev_result = await db.execute(select(Device).where(Device.id.in_(device_ids)))
devices_map = {d.id: d for d in dev_result.scalars().all()}
items = []
for e in events:
dev = devices_map.get(e.device_id)
items.append(AlertEventOut(
id=e.id,
device_id=e.device_id,
device_name=dev.name if dev else "系统",
device_ip=dev.ip if dev else "",
device_type=dev.device_type.value if dev else "",
location=dev.location if dev else "",
project_name=dev.project_name if dev else "",
alert_type=e.alert_type.value,
message=e.message,
start_at=e.start_at,
end_at=e.end_at,
duration_minutes=e.duration_minutes,
is_resolved=e.is_resolved,
notification_sent=e.notification_sent,
created_at=e.created_at,
))
return {"items": items, "total": total, "page": page, "page_size": page_size}
@router.get("/latest", response_model=list[AlertEventOut])
async def get_latest_alerts(
limit: int = Query(10, ge=1, le=50),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""获取最近的告警"""
result = await db.execute(
select(AlertEvent)
.order_by(AlertEvent.created_at.desc())
.limit(limit)
)
events = list(result.scalars().all())
device_ids = {e.device_id for e in events if e.device_id > 0}
devices_map = {}
if device_ids:
dev_result = await db.execute(select(Device).where(Device.id.in_(device_ids)))
devices_map = {d.id: d for d in dev_result.scalars().all()}
items = []
for e in events:
dev = devices_map.get(e.device_id)
items.append(AlertEventOut(
id=e.id,
device_id=e.device_id,
device_name=dev.name if dev else "系统",
device_ip=dev.ip if dev else "",
device_type=dev.device_type.value if dev else "",
location=dev.location if dev else "",
project_name=dev.project_name if dev else "",
alert_type=e.alert_type.value,
message=e.message,
start_at=e.start_at,
end_at=e.end_at,
duration_minutes=e.duration_minutes,
is_resolved=e.is_resolved,
notification_sent=e.notification_sent,
created_at=e.created_at,
))
return items