Replace servers nav with 3x-ui clients page showing enabled inbounds
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,12 +4,7 @@
|
||||
<div class="admin-top">
|
||||
<h1>Клиенты</h1>
|
||||
<div class="actions">
|
||||
<a class="btn btn-sm {% if tab == 'wg' %}btn-accent{% else %}btn-ghost{% endif %}" href="/admin/clients">WireGuard / AWG</a>
|
||||
<a class="btn btn-sm {% if tab == 'xui' %}btn-accent{% else %}btn-ghost{% endif %}" href="/admin/clients?source=xui">3x-ui</a>
|
||||
{% if tab == 'wg' %}
|
||||
<a class="btn btn-sm btn-ghost" href="/admin/clients?protocol=wireguard">WireGuard</a>
|
||||
<a class="btn btn-sm btn-ghost" href="/admin/clients?protocol=awg2">AWG 2.0</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-sm btn-accent" href="/admin/xui">Управление 3x-ui</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,90 +18,77 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if tab == 'wg' %}
|
||||
<div class="panel" style="margin-bottom:1rem">
|
||||
<div class="panel-head"><strong>Новый доступ (WireGuard / AWG)</strong></div>
|
||||
<div class="panel-body">
|
||||
<form method="post" action="/admin/clients" class="form-grid">
|
||||
<label>Имя
|
||||
<input name="name" placeholder="phone / laptop" required />
|
||||
</label>
|
||||
<label>Сервер / протокол
|
||||
<select name="server_id" required>
|
||||
{% for s in servers %}
|
||||
<option value="{{ s.id }}">{{ s.name }} ({{ s.protocol }})</option>
|
||||
{% else %}
|
||||
<option value="" disabled selected>Нет серверов</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<button class="btn btn-accent" type="submit" {% if not servers %}disabled{% endif %}>Создать</button>
|
||||
<label style="grid-column: 1 / -1">Заметка
|
||||
<input name="notes" placeholder="опционально" />
|
||||
</label>
|
||||
</form>
|
||||
<div class="panel-head">
|
||||
<strong>Доступные серверы 3x-ui</strong>
|
||||
<span class="muted">добавленные панели и inbound’ы, включённые для пользователей</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
{% if not xui_panels %}
|
||||
<div class="panel-body">
|
||||
<p class="muted" style="margin:0">Нет добавленных панелей. Подключите 3x-ui на странице <a href="/admin/xui">3x-ui</a>.</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Имя</th>
|
||||
<th>Протокол</th>
|
||||
<th>IP</th>
|
||||
<th>Сервер</th>
|
||||
<th>Статус</th>
|
||||
<th>Создан</th>
|
||||
<th>Inbound’ы для пользователей</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in clients %}
|
||||
{% for p in xui_panels %}
|
||||
{% set inbounds = user_inbounds_by_panel.get(p.id, []) %}
|
||||
<tr>
|
||||
<td><a href="/admin/clients/{{ c.id }}">{{ c.name }}</a></td>
|
||||
<td><span class="badge badge-proto">{{ c.server.protocol }}</span></td>
|
||||
<td>{{ c.address }}</td>
|
||||
<td>
|
||||
{% if c.is_enabled %}
|
||||
<span class="badge badge-ok">on</span>
|
||||
<strong>{{ p.name }}</strong>
|
||||
<div class="muted" style="font-size:.8rem;word-break:break-all">{{ p.base_url }}</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if p.is_reachable %}
|
||||
<span class="badge badge-ok">online</span>
|
||||
{% else %}
|
||||
<span class="badge badge-off">off</span>
|
||||
<span class="badge badge-off">offline</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="muted">{{ c.created_at.strftime('%Y-%m-%d %H:%M') if c.created_at else '—' }}</td>
|
||||
<td class="actions">
|
||||
<a class="btn btn-sm btn-ghost" href="/admin/clients/{{ c.id }}">Открыть</a>
|
||||
<form method="post" action="/admin/clients/{{ c.id }}/toggle" class="inline-form">
|
||||
<button class="btn btn-sm btn-ghost" type="submit">{% if c.is_enabled %}Выкл{% else %}Вкл{% endif %}</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/clients/{{ c.id }}/delete" class="inline-form" onsubmit="return confirm('Удалить клиента?')">
|
||||
<button class="btn btn-sm btn-danger" type="submit">Удалить</button>
|
||||
</form>
|
||||
<td>
|
||||
{% if inbounds %}
|
||||
<div style="display:flex;flex-wrap:wrap;gap:.35rem">
|
||||
{% for ib in inbounds %}
|
||||
<span class="badge badge-proto" title="port {{ ib.port or '?' }}">
|
||||
#{{ ib.inbound_id }} {{ ib.remark or ib.protocol }} · {{ ib.protocol }}{% if ib.port %}:{{ ib.port }}{% endif %}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="muted">нет включённых — откройте панель и отметьте inbound’ы</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-ghost" href="/admin/xui/{{ p.id }}">Настроить</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="muted">Клиентов пока нет</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
{# ——— 3x-ui ——— #}
|
||||
<div class="panel" style="margin-bottom:1rem">
|
||||
<div class="panel-head">
|
||||
<strong>Новый клиент 3x-ui</strong>
|
||||
<span class="muted">только inbound’ы, отмеченные на сервере как доступные пользователям</span>
|
||||
<strong>Новый клиент</strong>
|
||||
<span class="muted">только по включённым inbound’ам</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if not xui_panels %}
|
||||
<p class="muted" style="margin:0">Сначала добавьте панель на странице <a href="/admin/xui">3x-ui</a>.</p>
|
||||
{% if not panels_with_inbounds %}
|
||||
<p class="muted" style="margin:0">Нет серверов с включёнными inbound’ами. Добавьте панель в <a href="/admin/xui">3x-ui</a> и отметьте inbound’ы «для пользователей».</p>
|
||||
{% else %}
|
||||
<form method="post" action="/admin/clients/xui" class="stack" id="xui-client-form">
|
||||
<div class="form-grid">
|
||||
<label>Сервер 3x-ui
|
||||
<select name="panel_id" id="xui-panel" required>
|
||||
{% for p in xui_panels %}
|
||||
{% for p in panels_with_inbounds %}
|
||||
<option value="{{ p.id }}">{{ p.name }}{% if not p.is_reachable %} (offline){% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
@@ -147,15 +129,15 @@
|
||||
<label>Комментарий
|
||||
<input name="comment" />
|
||||
</label>
|
||||
<button class="btn btn-accent" type="submit" id="xui-submit" disabled>Создать в 3x-ui</button>
|
||||
<p class="muted" id="xui-inbound-hint" style="margin:0">Нет доступных inbound’ов — откройте сервер в <a href="/admin/xui">3x-ui</a> и отметьте нужные.</p>
|
||||
<button class="btn btn-accent" type="submit" id="xui-submit" disabled>Создать</button>
|
||||
<p class="muted" id="xui-inbound-hint" style="margin:0">Для выбранного протокола нет включённых inbound’ов.</p>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-head"><strong>Клиенты, созданные через сайт (3x-ui)</strong></div>
|
||||
<div class="panel-head"><strong>Клиенты через сайт</strong></div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -191,12 +173,13 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="7" class="muted">Клиентов 3x-ui пока нет</td></tr>
|
||||
<tr><td colspan="7" class="muted">Клиентов пока нет</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if panels_with_inbounds %}
|
||||
<script>
|
||||
(function () {
|
||||
const panelSelect = document.getElementById('xui-panel');
|
||||
|
||||
@@ -7,51 +7,49 @@
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat">
|
||||
<div class="label">Серверы</div>
|
||||
<div class="value">{{ servers|length }}</div>
|
||||
<div class="label">Панели 3x-ui</div>
|
||||
<div class="value">{{ xui_panels|length }}</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="label">Клиенты</div>
|
||||
<div class="value">{{ clients_total }}</div>
|
||||
<div class="label">Клиенты (сайт)</div>
|
||||
<div class="value">{{ xui_clients_total }}</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="label">Активные</div>
|
||||
<div class="value">{{ clients_active }}</div>
|
||||
<div class="label">Inbound’ы для пользователей</div>
|
||||
<div class="value">{{ user_inbounds_total }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-head">
|
||||
<strong>Протоколы</strong>
|
||||
<a class="btn btn-sm btn-accent" href="/admin/clients">Управлять клиентами</a>
|
||||
<strong>Серверы 3x-ui</strong>
|
||||
<a class="btn btn-sm btn-accent" href="/admin/clients">Клиенты</a>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Имя</th>
|
||||
<th>Протокол</th>
|
||||
<th>Endpoint</th>
|
||||
<th>Подсеть</th>
|
||||
<th>URL</th>
|
||||
<th>Статус</th>
|
||||
<th>Inbound’ы</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for s in servers %}
|
||||
{% for p in xui_panels %}
|
||||
<tr>
|
||||
<td>{{ s.name }}</td>
|
||||
<td><span class="badge badge-proto">{{ s.protocol }}</span></td>
|
||||
<td class="mono" style="background:transparent;color:inherit;padding:0">{{ s.public_host }}:{{ s.public_port }}</td>
|
||||
<td>{{ s.subnet }}</td>
|
||||
<td><a href="/admin/xui/{{ p.id }}">{{ p.name }}</a></td>
|
||||
<td class="muted" style="word-break:break-all">{{ p.base_url }}</td>
|
||||
<td>
|
||||
{% if s.is_enabled %}
|
||||
<span class="badge badge-ok">enabled</span>
|
||||
{% if p.is_reachable %}
|
||||
<span class="badge badge-ok">online</span>
|
||||
{% else %}
|
||||
<span class="badge badge-off">disabled</span>
|
||||
<span class="badge badge-off">offline</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="muted">{{ user_inbounds_by_panel.get(p.id, [])|length }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="5" class="muted">Серверы ещё не созданы</td></tr>
|
||||
<tr><td colspan="4" class="muted">Панели ещё не добавлены — <a href="/admin/xui">подключить 3x-ui</a></td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
</a>
|
||||
<nav>
|
||||
<a href="/admin" class="{% if request.url.path == '/admin' %}active{% endif %}">Дашборд</a>
|
||||
<a href="/admin/servers" class="{% if '/servers' in request.url.path %}active{% endif %}">Серверы</a>
|
||||
<a href="/admin/xui" class="{% if '/xui' in request.url.path %}active{% endif %}">3x-ui</a>
|
||||
<a href="/admin/clients" class="{% if '/clients' in request.url.path %}active{% endif %}">Клиенты</a>
|
||||
<a href="/" target="_blank">Сайт</a>
|
||||
|
||||
Reference in New Issue
Block a user