Files

117 lines
3.9 KiB
Python

from datetime import date, datetime
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_db
from app.models.announcement import Announcement
from app.models.schemas import AnnouncementListResponse, AnnouncementResponse
router = APIRouter()
def _parse_date(value: str | None) -> date | None:
if not value:
return None
return datetime.strptime(value, "%Y-%m-%d").date()
@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: str | None = None,
keyword: str | None = None,
start_date: str | None = None,
end_date: str | None = None,
crawl_mode: str | None = 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)
start = _parse_date(start_date)
end = _parse_date(end_date)
if start:
conditions.append(Announcement.publish_date >= start)
if end:
conditions.append(Announcement.publish_date <= end)
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/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) # noqa: E712
.select_from(Announcement)
)
unsent = await db.execute(
select(func.count()).where(
Announcement.is_sent == False, Announcement.is_new == True # noqa: E712
).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,
}
@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)