2025-08-02 12:38:52 +08:00

213 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
]
}