aa8af6c2e0
Flask + SQLite + Bootstrap5 暗色主题 - 仪表盘: 在线/离线统计 + 最近代理 + 操作日志 - 代理 CRUD: 增删改 + 启用/禁用 + 单/批量健康检测(SOCKS5) - 分组管理: 创建/删除/筛选 - 操作日志: 分页查询 - RESTful API + Web 界面 - 管理员登录认证 (SM_ADMIN_PASSWORD 环境变量)
59 lines
2.2 KiB
Python
59 lines
2.2 KiB
Python
import time
|
|
from datetime import datetime, timezone
|
|
from extensions import db
|
|
|
|
|
|
class Proxy(db.Model):
|
|
__tablename__ = "proxies"
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(128), nullable=False, index=True)
|
|
host = db.Column(db.String(256), nullable=False)
|
|
port = db.Column(db.Integer, nullable=False)
|
|
username = db.Column(db.String(128), nullable=True)
|
|
password = db.Column(db.String(256), nullable=True)
|
|
group_id = db.Column(db.Integer, db.ForeignKey("groups.id"), nullable=True)
|
|
enabled = db.Column(db.Boolean, default=True)
|
|
notes = db.Column(db.Text, nullable=True)
|
|
|
|
# 健康状态(由检测任务更新)
|
|
status = db.Column(db.String(16), default="unknown") # online/offline/unknown/error
|
|
latency_ms = db.Column(db.Float, nullable=True)
|
|
last_check = db.Column(db.DateTime, nullable=True)
|
|
|
|
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
|
|
updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc),
|
|
onupdate=lambda: datetime.now(timezone.utc))
|
|
|
|
group = db.relationship("Group", backref=db.backref("proxies", lazy=True))
|
|
|
|
def __repr__(self):
|
|
return f"<Proxy {self.name} {self.host}:{self.port}>"
|
|
|
|
|
|
class Group(db.Model):
|
|
__tablename__ = "groups"
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(128), nullable=False, unique=True)
|
|
color = db.Column(db.String(16), default="#6366f1")
|
|
description = db.Column(db.Text, nullable=True)
|
|
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
|
|
|
|
def __repr__(self):
|
|
return f"<Group {self.name}>"
|
|
|
|
|
|
class Log(db.Model):
|
|
__tablename__ = "logs"
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
timestamp = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
|
|
level = db.Column(db.String(16), default="INFO") # INFO/WARN/ERROR
|
|
action = db.Column(db.String(64), nullable=True) # add/update/delete/check
|
|
target = db.Column(db.String(128), nullable=True) # proxy/group name
|
|
detail = db.Column(db.Text, nullable=True)
|
|
|
|
def __repr__(self):
|
|
return f"<Log [{self.level}] {self.action}>"
|