from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from typing import List, Dict, Any from app.core.database import get_db from app.core.security import get_current_user from app.schemas.network import ScanTask, ScanTaskListResponse, ScanResult from app.models.network import TaskType, TaskStatus from app.services.scan_service import ScanService from app.services.network_service import NetworkService router = APIRouter( prefix="/scan", tags=["扫描管理"], dependencies=[Depends(get_current_user)], ) @router.get("/tasks", response_model=ScanTaskListResponse, summary="获取扫描任务列表") def get_scan_tasks( skip: int = 0, limit: int = 50, db: Session = Depends(get_db) ): """获取所有扫描任务""" total, items = ScanService.get_task_list(db, skip=skip, limit=limit) return {"total": total, "items": items} @router.get("/tasks/{task_id}", response_model=ScanTask, summary="获取扫描任务状态") def get_scan_task(task_id: int, db: Session = Depends(get_db)): """获取指定扫描任务的状态""" task = ScanService.get_task_by_id(db, task_id) if not task: raise HTTPException(status_code=404, detail="任务不存在") return task @router.post("/ping/{network_id}", response_model=ScanTask, status_code=201, summary="触发网段Ping扫描") def trigger_ping_scan(network_id: int, db: Session = Depends(get_db)): """对指定网段触发ICMP Ping扫描""" network = NetworkService.get_by_id(db, network_id) if not network: raise HTTPException(status_code=404, detail="网段不存在") # 创建扫描任务 task = ScanService.create_scan_task(db, TaskType.PING, network_id=network_id) # 立即执行扫描(简单版,后续用Celery) try: ScanService.update_task_status(db, task.id, TaskStatus.RUNNING, progress=0) # 执行扫描 results = ScanService.ping_network(network.cidr) # 更新IP状态 online_count, offline_count = ScanService.update_ip_status_from_scan_results(db, results) # 刷新网段统计字段(used_ips/reserved_ips),保证网段列表利用率能即时反映 NetworkService.get_stats(db, network_id) # 更新任务状态 ScanService.update_task_status( db, task.id, TaskStatus.COMPLETED, progress=100, total_count=len(results), success_count=online_count, failed_count=offline_count ) except Exception as e: ScanService.update_task_status( db, task.id, TaskStatus.FAILED, error_message=str(e) ) raise HTTPException(status_code=500, detail=f"扫描失败: {str(e)}") # 重新获取任务状态 task = ScanService.get_task_by_id(db, task.id) return task @router.post("/ping/single/{ip_address}", response_model=ScanResult, summary="单个IP Ping测试") def ping_single_ip(ip_address: str): """对单个IP执行Ping测试""" result = ScanService.ping_single_ip(ip_address) return { "ip_address": result["ip_address"], "status": result["status"], "mac_address": None, "hostname": None, "response_time": result.get("response_time") } @router.post("/refresh/stats", summary="刷新所有网段统计") def refresh_all_stats(db: Session = Depends(get_db)): """刷新所有网段的统计数据""" stats = NetworkService.get_all_stats(db) return { "message": "统计更新完成", "networks_updated": len(stats), "stats": stats }