from pydantic import BaseModel, Field, field_validator from typing import Optional, List, Dict, Any from datetime import datetime import ipaddress from app.models.network import IPStatus, TaskStatus, TaskType # ========== 网段相关 Schemas ========== class NetworkBase(BaseModel): cidr: str = Field(..., description="网段CIDR,如: 192.168.1.0/24") name: Optional[str] = Field(None, max_length=100, description="网段名称") description: Optional[str] = Field(None, description="描述") group_name: Optional[str] = Field(None, max_length=100, description="分组名称") gateway: Optional[str] = Field(None, max_length=50, description="网关地址") vlan_id: Optional[int] = Field(None, description="VLAN ID") @field_validator('cidr') @classmethod def validate_cidr(cls, v): try: network = ipaddress.ip_network(v, strict=False) return str(network) except ValueError: raise ValueError(f"无效的CIDR格式: {v}") @field_validator('gateway') @classmethod def validate_gateway(cls, v): if v: try: ipaddress.ip_address(v) except ValueError: raise ValueError(f"无效的IP地址: {v}") return v class NetworkCreate(NetworkBase): pass class NetworkUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None group_name: Optional[str] = None gateway: Optional[str] = None vlan_id: Optional[int] = None class Network(NetworkBase): id: int total_ips: int used_ips: int reserved_ips: int created_at: datetime updated_at: Optional[datetime] class Config: from_attributes = True class NetworkStats(BaseModel): """网段统计信息""" id: int cidr: str name: Optional[str] total_ips: int used_ips: int reserved_ips: int available_ips: int usage_percent: float group_name: Optional[str] vlan_id: Optional[int] class Config: from_attributes = True class NetworkListResponse(BaseModel): total: int items: List[Network] # ========== IP地址相关 Schemas ========== class IPAddressBase(BaseModel): ip_address: str mac_address: Optional[str] = None hostname: Optional[str] = None owner: Optional[str] = None business_type: Optional[str] = None notes: Optional[str] = None custom_fields: Dict[str, Any] = Field(default_factory=dict) switch_name: Optional[str] = None switch_port: Optional[str] = None vendor: Optional[str] = None class IPAddressCreate(IPAddressBase): network_id: int status: IPStatus = IPStatus.AVAILABLE class IPAddressUpdate(BaseModel): mac_address: Optional[str] = None hostname: Optional[str] = None status: Optional[IPStatus] = None owner: Optional[str] = None business_type: Optional[str] = None notes: Optional[str] = None custom_fields: Optional[Dict[str, Any]] = None class IPAddress(IPAddressBase): id: int network_id: int status: IPStatus last_seen: Optional[datetime] first_seen: datetime created_at: datetime updated_at: Optional[datetime] class Config: from_attributes = True class IPAddressListResponse(BaseModel): total: int items: List[IPAddress] # ========== 扫描任务相关 Schemas ========== class ScanTaskBase(BaseModel): task_type: TaskType network_id: Optional[int] = None class ScanTaskCreate(ScanTaskBase): pass class ScanTask(BaseModel): id: int network_id: Optional[int] task_type: TaskType status: TaskStatus progress: int celery_task_id: Optional[str] total_count: int success_count: int failed_count: int started_at: Optional[datetime] completed_at: Optional[datetime] error_message: Optional[str] created_at: datetime class Config: from_attributes = True class ScanTaskListResponse(BaseModel): total: int items: List[ScanTask] class ScanResult(BaseModel): """单次扫描结果""" ip_address: str status: str mac_address: Optional[str] = None hostname: Optional[str] = None response_time: Optional[float] = None