from sqlalchemy import Column, Integer, String, Text, DateTime, Enum, ForeignKey, JSON, Boolean from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base import enum class NetworkGroup(str, enum.Enum): """网段分组枚举""" PRODUCTION = "production" OFFICE = "office" TEST = "test" MANAGEMENT = "management" OTHER = "other" class IPStatus(str, enum.Enum): """IP状态枚举""" AVAILABLE = "available" ONLINE = "online" OFFLINE = "offline" RESERVED = "reserved" class TaskStatus(str, enum.Enum): """任务状态枚举""" PENDING = "pending" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" class TaskType(str, enum.Enum): """任务类型枚举""" PING = "ping" ARP = "arp" SNMP = "snmp" class Network(Base): """网段模型""" __tablename__ = "networks" id = Column(Integer, primary_key=True, index=True) cidr = Column(String(50), unique=True, index=True, nullable=False) # 如: 192.168.1.0/24 name = Column(String(100), index=True) description = Column(Text, nullable=True) group_name = Column(String(100), index=True, nullable=True) # 分组名称 gateway = Column(String(50), nullable=True) vlan_id = Column(Integer, nullable=True) total_ips = Column(Integer, default=0) used_ips = Column(Integer, default=0) reserved_ips = Column(Integer, default=0) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # 关系 ip_addresses = relationship("IPAddress", back_populates="network", cascade="all, delete-orphan") scan_tasks = relationship("ScanTask", back_populates="network") class IPAddress(Base): """IP地址模型""" __tablename__ = "ip_addresses" id = Column(Integer, primary_key=True, index=True) network_id = Column(Integer, ForeignKey("networks.id"), nullable=False) ip_address = Column(String(50), unique=True, index=True, nullable=False) mac_address = Column(String(50), nullable=True, index=True) hostname = Column(String(255), nullable=True) status = Column(Enum(IPStatus), default=IPStatus.AVAILABLE) # 业务属性 owner = Column(String(100), nullable=True) business_type = Column(String(50), nullable=True) notes = Column(Text, nullable=True) custom_fields = Column(JSON, default=dict) # 扫描信息 last_seen = Column(DateTime(timezone=True), nullable=True) first_seen = Column(DateTime(timezone=True), server_default=func.now()) # 物理位置信息 switch_name = Column(String(100), nullable=True) switch_port = Column(String(50), nullable=True) vendor = Column(String(100), nullable=True) # MAC OUI 解析的厂商 created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # 关系 network = relationship("Network", back_populates="ip_addresses") class ScanTask(Base): """扫描任务模型""" __tablename__ = "scan_tasks" id = Column(Integer, primary_key=True, index=True) network_id = Column(Integer, ForeignKey("networks.id"), nullable=True) task_type = Column(Enum(TaskType), nullable=False) status = Column(Enum(TaskStatus), default=TaskStatus.PENDING) progress = Column(Integer, default=0) # 0-100 celery_task_id = Column(String(100), nullable=True) # 统计信息 total_count = Column(Integer, default=0) success_count = Column(Integer, default=0) failed_count = Column(Integer, default=0) started_at = Column(DateTime(timezone=True), nullable=True) completed_at = Column(DateTime(timezone=True), nullable=True) error_message = Column(Text, nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) # 关系 network = relationship("Network", back_populates="scan_tasks")