Files
hive-manage-v3/backend/app/api/events.py
T
enzoandClaude eaf13e5f51 feat: Event archive management — Event model, migration, API, frontend page (Phase 8)
- Event ORM model with status/level enums, domain categories, review tracking
- Alembic migration e7f3a9b1c5d0 for events table
- Event crawler service with placeholder data (12 sample events)
- GET /api/v1/events with status/domain/search filtering and overdue_days
- EventArchivePage with filter toolbar (status, domain, search) and adaptive card grid
- Status badges, level badges, domain tags, overdue markers on event cards
- Loading/error/empty states, hover-to-honey card interaction

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 17:34:19 +08:00

66 lines
2.2 KiB
Python

"""Events API — 事件档案列表,三维筛选。"""
import logging
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.middleware.auth import require_auth
from app.models.event import Event, EventStatus, DOMAINS
from app.models.user import User
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/events", tags=["events"])
@router.get("")
async def list_events(
status: str | None = Query(None, description="按状态筛选"),
domain: str | None = Query(None, description="按领域筛选"),
search: str = Query("", description="按标题模糊搜索"),
_user: User = Depends(require_auth),
db: AsyncSession = Depends(get_db),
):
"""事件卡片列表,支持三维筛选。"""
stmt = select(Event).order_by(Event.occurred_date.desc())
valid_statuses = {s.value for s in EventStatus}
if status and status in valid_statuses:
stmt = stmt.where(Event.status == status)
if domain and domain in DOMAINS:
stmt = stmt.where(Event.domain == domain)
if search:
stmt = stmt.where(Event.title.ilike(f"%{search}%"))
result = await db.execute(stmt)
events = result.scalars().all()
now = datetime.now(timezone.utc)
data = []
for ev in events:
overdue_days = 0
if ev.next_review and ev.next_review < now:
overdue_days = (now - ev.next_review).days
data.append({
"id": ev.id,
"title": ev.title,
"level": ev.level.value,
"domain": ev.domain,
"status": ev.status.value,
"occurred_date": ev.occurred_date.isoformat(),
"last_reviewed": ev.last_reviewed.isoformat() if ev.last_reviewed else None,
"no_new_info_count": ev.no_new_info_count,
"next_review": ev.next_review.isoformat() if ev.next_review else None,
"overdue_days": overdue_days,
"created_at": ev.created_at.isoformat() if ev.created_at else None,
"updated_at": ev.updated_at.isoformat() if ev.updated_at else None,
})
return {"events": data}