from typing import Any, Dict, List from fastapi import APIRouter, Depends, Query from pydantic import BaseModel, Field from app.controllers.keyword import KeywordController from app.core.dependency import DependPermission from app.schemas.keyword import ( CrawlCompleteRequest, KeywordCreate, KeywordUpdate, PageProgressRequest, ) router = APIRouter(tags=["关键词接口"]) class MarkUsedRequest(BaseModel): source: str = Field(pattern="^(boss|qcwy|zhilian)$") ids: List[int] class StatsQuery(BaseModel): source: str = Field(pattern="^(boss|qcwy|zhilian)$") date: str | None = None async def get_keyword_controller() -> KeywordController: """获取关键词控制器实例 返回: 关键词控制器实例 """ return KeywordController() @router.get("/available", summary="获取当天未使用的检索条件") async def get_available( source: str, limit: int = 1, reserve: bool = True, crawler_id: str = "", controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """根据平台获取当天未使用的检索条件 优先级: partial(断点续爬) > failed(重试) > 全新关键词 """ return await controller.get_available(source, limit, reserve, crawler_id) @router.post("/mark-used", summary="将检索条件标记为今日已使用") async def mark_used( request: MarkUsedRequest, controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """将指定检索条件标记为今日已使用 参数: request: 包含平台标识与记录ID列表的请求体 返回: 更新结果,包含成功条数与日期 """ return await controller.mark_used(request.source, request.ids) @router.get("/stats", summary="统计使用与未使用数量") async def get_stats( source: str, date: str | None = None, controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """统计指定平台在某日期的使用与未使用数量 参数: source: 平台标识,boss|qcwy|zhilian date: 统计日期,格式 YYYY-MM-DD;不传则为今天 返回: 标准字典结构,包含 total/used/unused """ from datetime import date as _date d = None if date: try: y, m, d0 = map(int, date.split("-")) d = _date(y, m, d0) except Exception: d = None return await controller.get_stats(source, d) @router.get("/overview", summary="获取所有平台统计概览", dependencies=[DependPermission]) async def get_overview( controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """获取所有平台统计概览 返回: 各平台统计数据 """ return await controller.get_overview_stats() @router.get("/list", summary="获取关键词列表", dependencies=[DependPermission]) async def list_keywords( source: str = Query(..., pattern="^(boss|qcwy|zhilian)$"), page: int = 1, page_size: int = 20, city: str | None = None, job: str | None = None, controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """获取关键词列表 参数: source: 平台标识 page: 页码 page_size: 每页数量 city: 城市过滤 job: 职位过滤 返回: 列表数据 """ return await controller.list_keywords(source, page, page_size, city, job) @router.post("/create", summary="创建关键词", dependencies=[DependPermission]) async def create_keyword( item: KeywordCreate, source: str = Query(..., pattern="^(boss|qcwy|zhilian)$"), controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """创建关键词 参数: item: 关键词数据 source: 平台标识 返回: 创建结果 """ return await controller.create_keyword(source, item) @router.put("/update", summary="更新关键词", dependencies=[DependPermission]) async def update_keyword( id: int, item: KeywordUpdate, source: str = Query(..., pattern="^(boss|qcwy|zhilian)$"), controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """更新关键词 参数: id: 记录ID item: 更新数据 source: 平台标识 返回: 更新结果 """ return await controller.update_keyword(source, id, item) @router.delete("/delete", summary="删除关键词", dependencies=[DependPermission]) async def delete_keyword( id: int, source: str = Query(..., pattern="^(boss|qcwy|zhilian)$"), controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """删除关键词 参数: id: 记录ID source: 平台标识 返回: 删除结果 """ return await controller.delete_keyword(source, id) @router.post("/page-progress", summary="爬虫汇报单页爬取进度") async def report_page_progress( request: PageProgressRequest, controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """爬虫每完成一页后调用此接口汇报进度""" return await controller.report_page_progress( request.source, request.keyword_id, request.page, request.total_pages, request.jobs_found, ) @router.post("/crawl-complete", summary="爬虫汇报爬取完成或失败") async def report_crawl_complete( request: CrawlCompleteRequest, controller: KeywordController = Depends(get_keyword_controller), ) -> Dict[str, Any]: """爬虫完成或失败后调用此接口更新状态""" return await controller.report_crawl_complete( request.source, request.keyword_id, request.status, request.error_message, )