Files
socks-manager/templates/instances.html
T
Your Name 558bd8153f feat: 重构为 SOCKS5 代理管理平台 v2.0
架构:
- engine/server.py: asyncio SOCKS5 服务器引擎(含隧道/认证/限速)
- engine/instances.py: 多实例管理器(独立事件循环/热启动/热停止)
- services/user_service.py: 用户认证/流量统计/IP白名单/防爆破
- services/stats_service.py: 实时监控/流量趋势/连接追踪
- services/backup_service.py: 数据库备份与恢复
- api/v1.py: 完整 RESTful API
- web/routes.py: Web 管理面板(暗色 Bootstrap 5 主题)

功能覆盖:
 多实例 SOCKS5 管理(创建/启动/停止/重启/热加载)
 用户认证(无认证/账号密码/流量上限/限速/并发限制)
 IP 白名单/黑名单/防爆破
 实时仪表盘(CPU/内存/网络/活跃连接)
 流量统计(30天趋势图/用户排名/实例统计)
 活跃连接追踪
 审计日志(事件/用户/IP 筛选)
 数据库备份与恢复
 管理员密码保护
 16 项功能测试全部通过
2026-07-16 17:31:53 +08:00

239 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}代理实例 · SOCKS Manager{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0"><i class="bi bi-server"></i> 代理实例</h5>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addInstanceModal">
<i class="bi bi-plus-lg"></i> 新建实例</button>
</div>
<!-- 实例列表 -->
<div class="card">
<div class="card-body p-0">
<table class="table table-dark align-middle">
<thead>
<tr><th>名称</th><th>监听地址</th><th>认证</th><th>限速</th><th>并发</th>
<th>状态</th><th>活跃连接</th><th>操作</th></tr>
</thead>
<tbody>
{% for inst in instances %}
<tr>
<td>
<strong>{{ inst.name }}</strong>
{% if inst.notes %}<br><small class="text-muted">{{ inst.notes }}</small>{% endif %}
</td>
<td><code>{{ inst.host }}:{{ inst.port }}</code></td>
<td>
<span class="badge badge-{{ 'info' if inst.auth_method=='userpass' else 'secondary' }}">
{{ '账号密码' if inst.auth_method=='userpass' else '无认证' }}</span>
</td>
<td>
<span class="text-muted small">↓{{ inst.bandwidth_down or '不限' }} ↑{{ inst.bandwidth_up or '不限' }} Mbps</span>
</td>
<td>{{ inst.max_concurrent }}</td>
<td>
<span class="status-dot {{ 'dot-online' if inst.running else 'dot-offline' }}"></span>
{{ '运行中' if inst.running else '已停止' }}
</td>
<td>
<span class="badge badge-{{ 'success' if inst.active_connections>0 else 'secondary' }}">
{{ inst.active_connections }}</span>
</td>
<td>
<div class="btn-group btn-group-sm">
{% if not inst.running %}
<form method="post" action="/instances/{{ inst.id }}/start" style="display:inline">
<button class="btn btn-outline-success"><i class="bi bi-play-fill"></i></button>
</form>
{% else %}
<form method="post" action="/instances/{{ inst.id }}/stop" style="display:inline">
<button class="btn btn-outline-warning"><i class="bi bi-pause-fill"></i></button>
</form>
<form method="post" action="/instances/{{ inst.id }}/restart" style="display:inline">
<button class="btn btn-outline-primary"><i class="bi bi-arrow-clockwise"></i></button>
</form>
{% endif %}
<button class="btn btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#editInstanceModal"
data-name="{{ inst.name }}"
data-host="{{ inst.host }}"
data-port="{{ inst.port }}"
data-timeout="{{ inst.timeout }}"
data-auth="{{ inst.auth_method }}"
data-bw-down="{{ inst.bandwidth_down }}"
data-bw-up="{{ inst.bandwidth_up }}"
data-concurrent="{{ inst.max_concurrent }}"
data-notes="{{ inst.notes }}"
data-id="{{ inst.id }}">
<i class="bi bi-pencil"></i>
</button>
<form method="post" action="/instances/{{ inst.id }}/delete" style="display:inline"
onsubmit="return confirmDelete('确认删除实例 {{ inst.name }}')">
<button class="btn btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not instances %}
<div class="text-center py-5 text-muted">
<i class="bi bi-server text-muted" style="font-size:2rem;display:block;margin-bottom:.5rem"></i>
暂无实例,点击上方"新建实例"开始
</div>
{% endif %}
</div>
</div>
<!-- 添加实例模态框 -->
<div class="modal fade" id="addInstanceModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">新建代理实例</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="post" action="/instances/add">
<div class="modal-body">
<div class="mb-3"><label class="form-label">实例名称</label>
<input name="name" class="form-control" required placeholder="例: main-proxy">
</div>
<div class="row g-2 mb-3">
<div class="col-7">
<label class="form-label">监听地址</label>
<input name="listen_host" class="form-control" value="0.0.0.0" placeholder="0.0.0.0 或 ::">
</div>
<div class="col-5">
<label class="form-label">监听端口</label>
<input name="listen_port" type="number" class="form-control" value="1080" min="1" max="65535">
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">超时 (秒)</label>
<input name="timeout" type="number" class="form-control" value="30">
</div>
<div class="col-6">
<label class="form-label">认证方式</label>
<select name="auth_method" class="form-select">
<option value="none">无认证</option>
<option value="userpass">账号密码</option>
</select>
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">下行限速 (Mbps, 0=不限)</label>
<input name="bandwidth_down" type="number" class="form-control" value="0" step="0.1">
</div>
<div class="col-6">
<label class="form-label">上行限速 (Mbps, 0=不限)</label>
<input name="bandwidth_up" type="number" class="form-control" value="0" step="0.1">
</div>
</div>
<div class="mb-3">
<label class="form-label">最大并发连接数</label>
<input name="max_concurrent" type="number" class="form-control" value="10">
</div>
<div class="mb-3">
<label class="form-label">备注</label>
<textarea name="notes" class="form-control" rows="2"></textarea>
</div>
<div class="form-check">
<input type="checkbox" name="start" class="form-check-input" id="startCheck" checked>
<label class="form-check-label" for="startCheck">创建后立即启动</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">取消</button>
<button type="submit" class="btn btn-primary btn-sm">创建</button>
</div>
</form>
</div>
</div>
</div>
<!-- 编辑实例模态框 -->
<div class="modal fade" id="editInstanceModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">编辑实例</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="editInstanceForm" method="post">
<div class="modal-body">
<input type="hidden" name="id" id="editId">
<div class="row g-2 mb-3">
<div class="col-7">
<label class="form-label">监听地址</label>
<input name="listen_host" class="form-control" id="editHost">
</div>
<div class="col-5">
<label class="form-label">监听端口</label>
<input name="listen_port" type="number" class="form-control" id="editPort">
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">超时 (秒)</label>
<input name="timeout" type="number" class="form-control" id="editTimeout">
</div>
<div class="col-6">
<label class="form-label">认证方式</label>
<select name="auth_method" class="form-select" id="editAuth">
<option value="none">无认证</option>
<option value="userpass">账号密码</option>
</select>
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label">下行限速 (Mbps)</label>
<input name="bandwidth_down" type="number" class="form-control" id="editBwDown" step="0.1">
</div>
<div class="col-6">
<label class="form-label">上行限速 (Mbps)</label>
<input name="bandwidth_up" type="number" class="form-control" id="editBwUp" step="0.1">
</div>
</div>
<div class="mb-3">
<label class="form-label">最大并发连接数</label>
<input name="max_concurrent" type="number" class="form-control" id="editConcurrent">
</div>
<div class="mb-3">
<label class="form-label">备注</label>
<textarea name="notes" class="form-control" rows="2" id="editNotes"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">取消</button>
<button type="submit" class="btn btn-primary btn-sm">保存</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block extra_script %}
<script>
document.getElementById('editInstanceModal').addEventListener('show.bs.modal', function(e) {
const btn = e.relatedTarget;
const form = document.getElementById('editInstanceForm');
form.action = '/instances/' + btn.dataset.id + '/edit';
document.getElementById('editHost').value = btn.dataset.host;
document.getElementById('editPort').value = btn.dataset.port;
document.getElementById('editTimeout').value = btn.dataset.timeout;
document.getElementById('editAuth').value = btn.dataset.auth;
document.getElementById('editBwDown').value = btn.dataset.bwDown;
document.getElementById('editBwUp').value = btn.dataset.bwUp;
document.getElementById('editConcurrent').value = btn.dataset.concurrent;
document.getElementById('editNotes').value = btn.dataset.notes || '';
});
</script>
{% endblock %}