"""风险事件路由:CRUD + 状态流转。""" from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import get_db from app.core.dependencies import get_current_user from app.models.company import Company from app.models.risk import RiskEvent from app.models.user import User from app.schemas.common import ApiResponse, success from app.schemas.risk import ( RiskEventCreate, RiskEventListResponse, RiskEventResponse, RiskEventUpdate, ) router = APIRouter(prefix="/risks", tags=["risks"]) @router.get("", response_model=ApiResponse[RiskEventListResponse]) async def list_risks( company_id: str | None = Query(default=None), status_filter: str | None = Query(default=None, alias="status"), severity: str | None = Query(default=None), page: int = Query(default=1, ge=1), page_size: int = Query(default=20, ge=1, le=100), db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ): """获取风险事件列表。""" query = ( select(RiskEvent) .join(Company, RiskEvent.company_id == Company.id) .where(Company.tenant_id == user.tenant_id) ) if company_id: query = query.where(RiskEvent.company_id == company_id) if status_filter: query = query.where(RiskEvent.status == status_filter) if severity: query = query.where(RiskEvent.severity == severity) count_query = select(func.count()).select_from(query.subquery()) total_result = await db.execute(count_query) total = total_result.scalar_one() offset = (page - 1) * page_size query = query.order_by(RiskEvent.identified_at.desc()).offset(offset).limit(page_size) result = await db.execute(query) risks = result.scalars().all() return success( data=RiskEventListResponse( items=[RiskEventResponse.model_validate(r, from_attributes=True) for r in risks], total=total, page=page, page_size=page_size, ) ) @router.get("/{risk_id}", response_model=ApiResponse[RiskEventResponse]) async def get_risk( risk_id: str, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ): """获取风险事件详情。""" result = await db.execute( select(RiskEvent) .join(Company, RiskEvent.company_id == Company.id) .where(RiskEvent.id == risk_id, Company.tenant_id == user.tenant_id) ) risk = result.scalar_one_or_none() if not risk: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="风险事件不存在") return success(data=RiskEventResponse.model_validate(risk, from_attributes=True)) @router.post("", response_model=ApiResponse[RiskEventResponse], status_code=status.HTTP_201_CREATED) async def create_risk( req: RiskEventCreate, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ): """创建风险事件。""" # 验证企业属于租户 company_result = await db.execute( select(Company).where(Company.id == req.company_id, Company.tenant_id == user.tenant_id) ) if not company_result.scalar_one_or_none(): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="企业不存在") risk = RiskEvent( company_id=req.company_id, type=req.type, severity=req.severity, title=req.title, description=req.description, suggested_action=req.suggested_action, status="open", ) db.add(risk) await db.flush() return success( data=RiskEventResponse.model_validate(risk, from_attributes=True), message="创建成功", ) @router.put("/{risk_id}", response_model=ApiResponse[RiskEventResponse]) async def update_risk( risk_id: str, req: RiskEventUpdate, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ): """更新风险事件(状态流转等)。""" result = await db.execute( select(RiskEvent) .join(Company, RiskEvent.company_id == Company.id) .where(RiskEvent.id == risk_id, Company.tenant_id == user.tenant_id) ) risk = result.scalar_one_or_none() if not risk: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="风险事件不存在") update_data = req.model_dump(exclude_unset=True) for key, value in update_data.items(): setattr(risk, key, value) await db.flush() return success( data=RiskEventResponse.model_validate(risk, from_attributes=True), message="更新成功", ) @router.delete("/{risk_id}", response_model=ApiResponse[None]) async def delete_risk( risk_id: str, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ): """删除风险事件。""" result = await db.execute( select(RiskEvent) .join(Company, RiskEvent.company_id == Company.id) .where(RiskEvent.id == risk_id, Company.tenant_id == user.tenant_id) ) risk = result.scalar_one_or_none() if not risk: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="风险事件不存在") await db.delete(risk) return success(message="删除成功")