213 lines
7.2 KiB
Python
213 lines
7.2 KiB
Python
![]() |
from fastapi import APIRouter, Depends, HTTPException, Query
|
|||
|
from sqlalchemy.orm import Session
|
|||
|
from typing import List, Optional
|
|||
|
from datetime import datetime
|
|||
|
from core.database import get_db
|
|||
|
from models.event import Event
|
|||
|
from schemas.event import (
|
|||
|
EventCreate,
|
|||
|
EventUpdate,
|
|||
|
EventResponse,
|
|||
|
EventListResponse
|
|||
|
)
|
|||
|
|
|||
|
router = APIRouter()
|
|||
|
|
|||
|
@router.post("/", response_model=EventResponse, summary="创建事件")
|
|||
|
async def create_event(
|
|||
|
event: EventCreate,
|
|||
|
db: Session = Depends(get_db)
|
|||
|
):
|
|||
|
"""创建新的事件"""
|
|||
|
db_event = Event(**event.dict())
|
|||
|
db.add(db_event)
|
|||
|
db.commit()
|
|||
|
db.refresh(db_event)
|
|||
|
return db_event
|
|||
|
|
|||
|
@router.get("/", response_model=EventListResponse, summary="获取事件列表")
|
|||
|
async def get_events(
|
|||
|
skip: int = Query(0, ge=0, description="跳过记录数"),
|
|||
|
limit: int = Query(10, ge=1, le=100, description="返回记录数"),
|
|||
|
event_type: Optional[str] = Query(None, description="事件类型"),
|
|||
|
device_id: Optional[int] = Query(None, description="设备ID"),
|
|||
|
algorithm_id: Optional[int] = Query(None, description="算法ID"),
|
|||
|
severity: Optional[str] = Query(None, description="严重程度"),
|
|||
|
status: Optional[str] = Query(None, description="事件状态"),
|
|||
|
is_alert: Optional[bool] = Query(None, description="是否告警"),
|
|||
|
start_time: Optional[str] = Query(None, description="开始时间"),
|
|||
|
end_time: Optional[str] = Query(None, description="结束时间"),
|
|||
|
db: Session = Depends(get_db)
|
|||
|
):
|
|||
|
"""获取事件列表,支持分页和筛选"""
|
|||
|
query = db.query(Event)
|
|||
|
|
|||
|
if event_type:
|
|||
|
query = query.filter(Event.event_type == event_type)
|
|||
|
if device_id:
|
|||
|
query = query.filter(Event.device_id == device_id)
|
|||
|
if algorithm_id:
|
|||
|
query = query.filter(Event.algorithm_id == algorithm_id)
|
|||
|
if severity:
|
|||
|
query = query.filter(Event.severity == severity)
|
|||
|
if status:
|
|||
|
query = query.filter(Event.status == status)
|
|||
|
if is_alert is not None:
|
|||
|
query = query.filter(Event.is_alert == is_alert)
|
|||
|
if start_time:
|
|||
|
try:
|
|||
|
start_dt = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
|
|||
|
query = query.filter(Event.created_at >= start_dt)
|
|||
|
except ValueError:
|
|||
|
pass
|
|||
|
if end_time:
|
|||
|
try:
|
|||
|
end_dt = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
|
|||
|
query = query.filter(Event.created_at <= end_dt)
|
|||
|
except ValueError:
|
|||
|
pass
|
|||
|
|
|||
|
# 按创建时间倒序排列
|
|||
|
query = query.order_by(Event.created_at.desc())
|
|||
|
|
|||
|
total = query.count()
|
|||
|
events = query.offset(skip).limit(limit).all()
|
|||
|
|
|||
|
return EventListResponse(
|
|||
|
events=events,
|
|||
|
total=total,
|
|||
|
page=skip // limit + 1,
|
|||
|
size=limit
|
|||
|
)
|
|||
|
|
|||
|
@router.get("/{event_id}", response_model=EventResponse, summary="获取事件详情")
|
|||
|
async def get_event(
|
|||
|
event_id: int,
|
|||
|
db: Session = Depends(get_db)
|
|||
|
):
|
|||
|
"""根据ID获取事件详情"""
|
|||
|
event = db.query(Event).filter(Event.id == event_id).first()
|
|||
|
if not event:
|
|||
|
raise HTTPException(status_code=404, detail="事件不存在")
|
|||
|
return event
|
|||
|
|
|||
|
@router.put("/{event_id}", response_model=EventResponse, summary="更新事件")
|
|||
|
async def update_event(
|
|||
|
event_id: int,
|
|||
|
event: EventUpdate,
|
|||
|
db: Session = Depends(get_db)
|
|||
|
):
|
|||
|
"""更新事件信息"""
|
|||
|
db_event = db.query(Event).filter(Event.id == event_id).first()
|
|||
|
if not db_event:
|
|||
|
raise HTTPException(status_code=404, detail="事件不存在")
|
|||
|
|
|||
|
update_data = event.dict(exclude_unset=True)
|
|||
|
for field, value in update_data.items():
|
|||
|
setattr(db_event, field, value)
|
|||
|
|
|||
|
db.commit()
|
|||
|
db.refresh(db_event)
|
|||
|
return db_event
|
|||
|
|
|||
|
@router.delete("/{event_id}", summary="删除事件")
|
|||
|
async def delete_event(
|
|||
|
event_id: int,
|
|||
|
db: Session = Depends(get_db)
|
|||
|
):
|
|||
|
"""删除事件"""
|
|||
|
event = db.query(Event).filter(Event.id == event_id).first()
|
|||
|
if not event:
|
|||
|
raise HTTPException(status_code=404, detail="事件不存在")
|
|||
|
|
|||
|
db.delete(event)
|
|||
|
db.commit()
|
|||
|
return {"message": "事件删除成功"}
|
|||
|
|
|||
|
@router.patch("/{event_id}/status", response_model=EventResponse, summary="更新事件状态")
|
|||
|
async def update_event_status(
|
|||
|
event_id: int,
|
|||
|
status: str = Query(..., description="新状态"),
|
|||
|
resolution_notes: Optional[str] = Query(None, description="处理备注"),
|
|||
|
db: Session = Depends(get_db)
|
|||
|
):
|
|||
|
"""更新事件状态"""
|
|||
|
event = db.query(Event).filter(Event.id == event_id).first()
|
|||
|
if not event:
|
|||
|
raise HTTPException(status_code=404, detail="事件不存在")
|
|||
|
|
|||
|
event.status = status
|
|||
|
if resolution_notes:
|
|||
|
event.resolution_notes = resolution_notes
|
|||
|
|
|||
|
# 如果状态为resolved,设置解决时间
|
|||
|
if status == "resolved":
|
|||
|
event.resolved_at = datetime.utcnow()
|
|||
|
|
|||
|
db.commit()
|
|||
|
db.refresh(event)
|
|||
|
return event
|
|||
|
|
|||
|
@router.get("/types/list", summary="获取事件类型列表")
|
|||
|
async def get_event_types():
|
|||
|
"""获取所有事件类型"""
|
|||
|
return {
|
|||
|
"types": [
|
|||
|
{"value": "person_detection", "label": "人员检测"},
|
|||
|
{"value": "vehicle_detection", "label": "车辆检测"},
|
|||
|
{"value": "intrusion", "label": "入侵检测"},
|
|||
|
{"value": "face_recognition", "label": "人脸识别"},
|
|||
|
{"value": "license_plate", "label": "车牌识别"},
|
|||
|
{"value": "object_detection", "label": "物体检测"},
|
|||
|
{"value": "behavior_analysis", "label": "行为分析"},
|
|||
|
{"value": "other", "label": "其他"}
|
|||
|
]
|
|||
|
}
|
|||
|
|
|||
|
@router.get("/stats/summary", summary="获取事件统计摘要")
|
|||
|
async def get_event_stats_summary(db: Session = Depends(get_db)):
|
|||
|
"""获取事件统计摘要"""
|
|||
|
total = db.query(Event).count()
|
|||
|
pending = db.query(Event).filter(Event.status == "pending").count()
|
|||
|
processing = db.query(Event).filter(Event.status == "processing").count()
|
|||
|
resolved = db.query(Event).filter(Event.status == "resolved").count()
|
|||
|
ignored = db.query(Event).filter(Event.status == "ignored").count()
|
|||
|
alerts = db.query(Event).filter(Event.is_alert == True).count()
|
|||
|
|
|||
|
# 按严重程度统计
|
|||
|
critical = db.query(Event).filter(Event.severity == "critical").count()
|
|||
|
high = db.query(Event).filter(Event.severity == "high").count()
|
|||
|
medium = db.query(Event).filter(Event.severity == "medium").count()
|
|||
|
low = db.query(Event).filter(Event.severity == "low").count()
|
|||
|
|
|||
|
return {
|
|||
|
"total": total,
|
|||
|
"pending": pending,
|
|||
|
"processing": processing,
|
|||
|
"resolved": resolved,
|
|||
|
"ignored": ignored,
|
|||
|
"alerts": alerts,
|
|||
|
"severity": {
|
|||
|
"critical": critical,
|
|||
|
"high": high,
|
|||
|
"medium": medium,
|
|||
|
"low": low
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@router.get("/stats/by-type", summary="按类型统计事件")
|
|||
|
async def get_event_stats_by_type(db: Session = Depends(get_db)):
|
|||
|
"""按事件类型统计"""
|
|||
|
from sqlalchemy import func
|
|||
|
|
|||
|
stats = db.query(
|
|||
|
Event.event_type,
|
|||
|
func.count(Event.id).label('count')
|
|||
|
).group_by(Event.event_type).all()
|
|||
|
|
|||
|
return {
|
|||
|
"stats": [
|
|||
|
{"type": stat.event_type, "count": stat.count}
|
|||
|
for stat in stats
|
|||
|
]
|
|||
|
}
|