Files
GX-gp-notify/app/api/announcements.py
T

108 lines
3.8 KiB
Python

from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Query, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from app.api.deps import get_db
from app.models.announcement import Announcement
from app.models.schemas import AnnouncementResponse, AnnouncementListResponse
router = APIRouter()
@router.get("/announcements", response_model=AnnouncementListResponse)
async def list_announcements(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
source_code: Optional[str] = None,
keyword: Optional[str] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
crawl_mode: Optional[str] = None,
db: AsyncSession = Depends(get_db),
):
conditions = []
if source_code:
conditions.append(Announcement.source_code == source_code)
if crawl_mode:
conditions.append(Announcement.crawl_mode == crawl_mode)
if start_date:
conditions.append(Announcement.publish_date >= start_date)
if end_date:
conditions.append(Announcement.publish_date <= end_date)
if keyword:
conditions.append(
Announcement.title.ilike(f"%{keyword}%")
)
base_query = select(Announcement)
if conditions:
base_query = base_query.where(*conditions)
count_query = select(func.count()).select_from(base_query.subquery())
total_result = await db.execute(count_query)
total = total_result.scalar() or 0
items_query = base_query.order_by(Announcement.publish_date.desc()) \
.offset((page - 1) * page_size).limit(page_size)
items_result = await db.execute(items_query)
items = items_result.scalars().all()
return AnnouncementListResponse(
total=total,
page=page,
page_size=page_size,
items=[AnnouncementResponse.model_validate(item) for item in items],
)
@router.get("/announcements/{announcement_id}", response_model=AnnouncementResponse)
async def get_announcement(announcement_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(Announcement).where(Announcement.id == announcement_id)
)
item = result.scalar_one_or_none()
if item is None:
raise HTTPException(status_code=404, detail="公告不存在")
return AnnouncementResponse.model_validate(item)
@router.get("/announcements/today", response_model=AnnouncementListResponse)
async def get_today_announcements(db: AsyncSession = Depends(get_db)):
today = datetime.now().date()
result = await db.execute(
select(Announcement).where(
func.date(Announcement.publish_date) == today
).order_by(Announcement.publish_date.desc())
)
items = result.scalars().all()
return AnnouncementListResponse(
total=len(items), page=1, page_size=len(items),
items=[AnnouncementResponse.model_validate(item) for item in items],
)
@router.get("/announcements/stats")
async def get_stats(db: AsyncSession = Depends(get_db)):
total = await db.execute(select(func.count()).select_from(Announcement))
today_count = await db.execute(
select(func.count()).where(
func.date(Announcement.publish_date) == func.current_date()
).select_from(Announcement)
)
new_count = await db.execute(
select(func.count()).where(Announcement.is_new == True)
.select_from(Announcement)
)
unsent = await db.execute(
select(func.count()).where(
Announcement.is_sent == False, Announcement.is_new == True
).select_from(Announcement)
)
return {
"total": total.scalar() or 0,
"today": today_count.scalar() or 0,
"new": new_count.scalar() or 0,
"unsent": unsent.scalar() or 0,
}