""" Review Cards API Routes 审核卡片API路由 - 提供审核卡片的CRUD操作 """ from fastapi import APIRouter, Depends, HTTPException, Query from typing import List, Optional from datetime import datetime from app.models.review_card import ( ReviewCard, ReviewCardCreate, ReviewCardUpdate, ReviewCardType, ReviewCardStatus ) from app.db.review_card_repository import get_review_card_repo from app.api.v1.websocket import manager from app.utils.logger import get_logger logger = get_logger(__name__) router = APIRouter(prefix="/review-cards", tags=["审核卡片"]) # ============================================ # 依赖注入 # ============================================ async def get_repo(): """获取审核卡片仓储""" return get_review_card_repo() # ============================================ # CRUD 端点 # ============================================ @router.post("") async def create_review_card( data: ReviewCardCreate, repo=Depends(get_repo) ): """ 创建审核卡片 触发场景: 1. Agent生成剧集内容后自动生成 2. 用户在对话框触发某一集/某几集/整个剧集的审核 """ try: card = await repo.create(data) # 通过WebSocket推送通知 await manager.send_to_project(data.project_id, { "type": "review_card_created", "data": { "card_id": card.id, "card_type": card.card_type.value, "episode_numbers": card.episode_numbers, "severity": card.severity, "review_reason": card.review_reason, "created_at": card.created_at.isoformat() } }) logger.info(f"创建审核卡片成功: {card.id}") return {"success": True, "card": card} except Exception as e: logger.error(f"创建审核卡片失败: {str(e)}") raise HTTPException(status_code=500, detail=f"创建审核卡片失败: {str(e)}") @router.get("") async def list_review_cards( project_id: str, status: Optional[ReviewCardStatus] = None, card_type: Optional[ReviewCardType] = None, limit: int = Query(100, ge=1, le=500), repo=Depends(get_repo) ) -> List[ReviewCard]: """ 获取审核卡片列表 支持按状态和类型筛选 """ try: cards = await repo.list_by_project(project_id, status, limit) if card_type: cards = [c for c in cards if c.card_type == card_type] return cards except Exception as e: logger.error(f"获取审核卡片列表失败: {str(e)}") raise HTTPException(status_code=500, detail=f"获取列表失败: {str(e)}") @router.get("/stats/{project_id}") async def get_review_card_stats( project_id: str, repo=Depends(get_repo) ): """ 获取审核卡片统计信息 返回各类状态的数量统计 """ try: total = await repo.count_by_project(project_id) pending = await repo.count_by_status(project_id, ReviewCardStatus.PENDING) awaiting_user = await repo.count_by_status(project_id, ReviewCardStatus.AWAITING_USER) approved = await repo.count_by_status(project_id, ReviewCardStatus.APPROVED) rejected = await repo.count_by_status(project_id, ReviewCardStatus.REJECTED) return { "total": total, "pending": pending, "awaiting_user": awaiting_user, "approved": approved, "rejected": rejected } except Exception as e: logger.error(f"获取审核卡片统计失败: {str(e)}") raise HTTPException(status_code=500, detail=f"获取统计失败: {str(e)}") @router.get("/{card_id}") async def get_review_card( card_id: str, repo=Depends(get_repo) ) -> ReviewCard: """获取审核卡片详情""" card = await repo.get(card_id) if not card: raise HTTPException(status_code=404, detail="审核卡片不存在") return card @router.put("/{card_id}") async def update_review_card( card_id: str, data: ReviewCardUpdate, repo=Depends(get_repo) ): """ 更新审核卡片 支持更新状态、用户评论、修改内容等 """ try: card = await repo.update(card_id, data) if not card: raise HTTPException(status_code=404, detail="审核卡片不存在") # 通知WebSocket await manager.send_to_project(card.project_id, { "type": "review_card_updated", "data": { "card_id": card_id, "status": card.status.value, "updated_at": card.updated_at.isoformat() } }) logger.info(f"更新审核卡片成功: {card_id}") return {"success": True, "card": card} except HTTPException: raise except Exception as e: logger.error(f"更新审核卡片失败: {str(e)}") raise HTTPException(status_code=500, detail=f"更新失败: {str(e)}") @router.delete("/{card_id}") async def delete_review_card( card_id: str, repo=Depends(get_repo) ): """删除审核卡片""" try: success = await repo.delete(card_id) if not success: raise HTTPException(status_code=404, detail="审核卡片不存在") logger.info(f"删除审核卡片成功: {card_id}") return {"success": True} except HTTPException: raise except Exception as e: logger.error(f"删除审核卡片失败: {str(e)}") raise HTTPException(status_code=500, detail=f"删除失败: {str(e)}") # ============================================ # 操作端点 # ============================================ @router.post("/{card_id}/approve") async def approve_review_card( card_id: str, user_comment: Optional[str] = None, repo=Depends(get_repo) ): """ 通过审核卡片 将卡片状态设置为APPROVED """ try: update_data = ReviewCardUpdate( status=ReviewCardStatus.APPROVED, user_comment=user_comment ) result = await update_review_card(card_id, update_data, repo) return result except Exception as e: logger.error(f"通过审核卡片失败: {str(e)}") raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}") @router.post("/{card_id}/reject") async def reject_review_card( card_id: str, user_comment: Optional[str] = None, modified_content: Optional[str] = None, repo=Depends(get_repo) ): """ 驳回审核卡片 将卡片状态设置为REJECTED,可选地包含修改内容 """ try: update_data = ReviewCardUpdate( status=ReviewCardStatus.REJECTED, user_comment=user_comment, modified_content=modified_content ) result = await update_review_card(card_id, update_data, repo) return result except Exception as e: logger.error(f"驳回审核卡片失败: {str(e)}") raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}") @router.post("/{card_id}/modify") async def modify_review_card( card_id: str, user_comment: Optional[str] = None, modified_content: Optional[str] = None, repo=Depends(get_repo) ): """ 修改审核卡片内容 将卡片状态设置为MODIFIED,包含修改后的内容 """ try: update_data = ReviewCardUpdate( status=ReviewCardStatus.AWAITING_USER, user_comment=user_comment, modified_content=modified_content ) result = await update_review_card(card_id, update_data, repo) return result except Exception as e: logger.error(f"修改审核卡片失败: {str(e)}") raise HTTPException(status_code=500, detail=f"操作失败: {str(e)}")