forked from test2/Amnezia-Web-Panel-main
Load inbounds from 3x-ui and use panel share links only.
Restore inbound selection from the panel API and send a minimal addClient payload so locally invented fields do not break configs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+45
-5
@@ -44,6 +44,7 @@
|
||||
<div style="font-size:0.8rem; color:var(--text-muted); margin-top:2px;">
|
||||
{% if inv.protocol == 'xui' %}
|
||||
3x-ui · {% for s in xui_servers if s.id == inv.xui_panel_id %}{{ s.name }}{% else %}{{ _('xui_server_select_label') }}{% endfor %}
|
||||
· inbound #{{ inv.xui_inbound_id or '—' }}
|
||||
{% else %}
|
||||
{{ inv.protocol }}
|
||||
{% endif %}
|
||||
@@ -141,12 +142,17 @@
|
||||
|
||||
<div class="form-group" id="inviteInboundGroup">
|
||||
<label class="form-label">{{ _('xui_server_select_label') }}</label>
|
||||
<select class="form-select" id="inviteXuiPanel">
|
||||
<select class="form-select" id="inviteXuiPanel" onchange="loadInviteInbounds()">
|
||||
{% for s in xui_servers %}
|
||||
<option value="{{ s.id }}">{{ s.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-hint">{{ _('xui_server_select_hint') }}</div>
|
||||
<label class="form-label" style="margin-top:var(--space-sm);">{{ _('xui_inbound_label') }}</label>
|
||||
<select class="form-select" id="inviteInboundId">
|
||||
<option value="">{{ _('invite_inbound_loading') }}</option>
|
||||
</select>
|
||||
<div class="form-hint">{{ _('invite_inbound_hint') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -181,6 +187,7 @@
|
||||
<script>
|
||||
const invitesData = {{ invites | tojson }};
|
||||
const xuiConfigured = {{ 'true' if xui_configured else 'false' }};
|
||||
const xuiDefaultInbound = {{ xui_default_inbound | int }};
|
||||
const xuiDefaultPanelId = {{ (xui_default_panel_id or '') | tojson }};
|
||||
|
||||
function inviteUrl(token) {
|
||||
@@ -195,6 +202,38 @@
|
||||
function updateInviteProtoFields() {
|
||||
const v = document.getElementById('inviteProtocol').value;
|
||||
document.getElementById('inviteInboundGroup').style.display = (v === 'xui') ? '' : 'none';
|
||||
if (v === 'xui') loadInviteInbounds(document.getElementById('inviteInboundId').value || xuiDefaultInbound);
|
||||
}
|
||||
|
||||
async function loadInviteInbounds(selected) {
|
||||
const select = document.getElementById('inviteInboundId');
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_loading')}</option>`;
|
||||
if (!xuiConfigured) {
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_need_xui')}</option>`;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const panelId = document.getElementById('inviteXuiPanel')?.value || xuiDefaultPanelId || '';
|
||||
const q = panelId ? `?panel_id=${encodeURIComponent(panelId)}` : '';
|
||||
const data = await apiCall('/api/settings/xui/inbounds' + q);
|
||||
const list = data.inbounds || [];
|
||||
if (!list.length) {
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_empty')}</option>`;
|
||||
return;
|
||||
}
|
||||
select.innerHTML = '';
|
||||
list.forEach((ib, idx) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = ib.id;
|
||||
opt.textContent = `${ib.remark || 'VLESS'} (:${ib.port})`;
|
||||
const prefer = selected || xuiDefaultInbound;
|
||||
if (prefer && String(ib.id) === String(prefer)) opt.selected = true;
|
||||
else if (!prefer && idx === 0) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
} catch (e) {
|
||||
select.innerHTML = `<option value="">${_('error')}: ${e.message}</option>`;
|
||||
}
|
||||
}
|
||||
|
||||
function parseProtocolValue() {
|
||||
@@ -234,6 +273,7 @@
|
||||
const p = document.getElementById('inviteXuiPanel');
|
||||
if (p && [...p.options].some(o => o.value === xuiDefaultPanelId)) p.value = xuiDefaultPanelId;
|
||||
}
|
||||
loadInviteInbounds(xuiDefaultInbound);
|
||||
openModal('inviteModal');
|
||||
}
|
||||
|
||||
@@ -257,6 +297,7 @@
|
||||
if (panelSel && inv.xui_panel_id && [...panelSel.options].some(o => o.value === inv.xui_panel_id)) {
|
||||
panelSel.value = inv.xui_panel_id;
|
||||
}
|
||||
loadInviteInbounds(inv.xui_inbound_id || xuiDefaultInbound);
|
||||
openModal('inviteModal');
|
||||
}
|
||||
|
||||
@@ -268,9 +309,8 @@
|
||||
try {
|
||||
const editId = document.getElementById('inviteEditId').value;
|
||||
const proto = parseProtocolValue();
|
||||
if (proto.protocol === 'xui' && !document.getElementById('inviteXuiPanel')?.value) {
|
||||
throw new Error(_('invite_inbound_need_xui'));
|
||||
}
|
||||
const inbound = parseInt(document.getElementById('inviteInboundId').value || '0');
|
||||
if (proto.protocol === 'xui' && !inbound) throw new Error(_('invite_inbound_required'));
|
||||
|
||||
const body = {
|
||||
name: document.getElementById('inviteName').value || 'Invite',
|
||||
@@ -279,7 +319,7 @@
|
||||
user_id: document.getElementById('inviteUserId').value || '',
|
||||
protocol: proto.protocol,
|
||||
server_id: proto.server_id,
|
||||
xui_inbound_id: 0,
|
||||
xui_inbound_id: inbound,
|
||||
xui_panel_id: document.getElementById('inviteXuiPanel')?.value || '',
|
||||
note: document.getElementById('inviteNote').value || '',
|
||||
};
|
||||
|
||||
+48
-6
@@ -127,13 +127,16 @@
|
||||
</div>
|
||||
<div class="form-group" id="guestInboundGroup" style="{% if settings.guest.create_protocol != 'xui' %}display:none;{% endif %}">
|
||||
<label class="form-label">{{ _('xui_server_select_label') }}</label>
|
||||
<select class="form-select" id="guest_create_xui_panel">
|
||||
<select class="form-select" id="guest_create_xui_panel" onchange="loadGuestInbounds()">
|
||||
{% for s in xui_servers %}
|
||||
<option value="{{ s.id }}" {% if settings.guest.create_xui_panel_id == s.id %}selected{% endif %}>{{ s.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-hint">{{ _('xui_server_select_hint') }}</div>
|
||||
<input type="hidden" id="guest_create_inbound_id" value="0">
|
||||
<label class="form-label" style="margin-top:var(--space-sm);">{{ _('xui_inbound_label') }}</label>
|
||||
<select class="form-select" id="guest_create_inbound_id">
|
||||
<option value="0">{{ _('invite_inbound_loading') }}</option>
|
||||
</select>
|
||||
<div class="form-hint">{{ _('xui_inbound_hint') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -850,9 +853,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Inbound + share link are assigned by the selected 3x-ui panel on create
|
||||
async function loadXuiInbounds() {}
|
||||
async function loadGuestInbounds() {}
|
||||
// Load VLESS inbounds from the selected 3x-ui panel
|
||||
async function loadXuiInbounds() {
|
||||
await loadGuestInbounds();
|
||||
}
|
||||
|
||||
async function loadGuestInbounds() {
|
||||
const select = document.getElementById('guest_create_inbound_id');
|
||||
if (!select) return;
|
||||
const preferred = {{ settings.guest.create_inbound_id | default(0) | int }};
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_loading')}</option>`;
|
||||
try {
|
||||
const panelSel = document.getElementById('guest_create_xui_panel');
|
||||
const panelId = panelSel ? panelSel.value : '';
|
||||
const q = panelId ? `?panel_id=${encodeURIComponent(panelId)}` : '';
|
||||
const res = await fetch('/api/settings/xui/inbounds' + q);
|
||||
const data = await res.json();
|
||||
if (!res.ok) throw new Error(data.error || 'Failed to load inbounds');
|
||||
const list = data.inbounds || [];
|
||||
if (!list.length) {
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_empty')}</option>`;
|
||||
return;
|
||||
}
|
||||
select.innerHTML = '';
|
||||
list.forEach((ib, idx) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = ib.id;
|
||||
opt.textContent = `${ib.remark || 'VLESS'} (:${ib.port})`;
|
||||
if (preferred && String(ib.id) === String(preferred)) opt.selected = true;
|
||||
else if (!preferred && idx === 0) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('loadGuestInbounds:', err);
|
||||
select.innerHTML = `<option value="">${_('error')}: ${err.message}</option>`;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('syncCreateConns').addEventListener('change', (e) => {
|
||||
document.getElementById('autoConnFields').style.display = e.target.checked ? 'block' : 'none';
|
||||
@@ -1286,6 +1322,12 @@
|
||||
const v = document.getElementById('guest_create_protocol')?.value;
|
||||
const group = document.getElementById('guestInboundGroup');
|
||||
if (group) group.style.display = (v === 'xui') ? 'block' : 'none';
|
||||
if (v === 'xui') loadGuestInbounds();
|
||||
}
|
||||
|
||||
// Prefill guest inbound list when page opens on 3x-ui
|
||||
if (document.getElementById('guest_create_protocol')?.value === 'xui') {
|
||||
loadGuestInbounds();
|
||||
}
|
||||
|
||||
function copyGuestLink() {
|
||||
|
||||
+39
-4
@@ -293,12 +293,16 @@
|
||||
|
||||
<div class="form-group" id="ucXuiInboundGroup" style="display:none;">
|
||||
<label class="form-label">{{ _('xui_server_select_label') }}</label>
|
||||
<select class="form-select" id="ucXuiPanel">
|
||||
<select class="form-select" id="ucXuiPanel" onchange="loadXuiInbounds()">
|
||||
{% for s in xui_servers %}
|
||||
<option value="{{ s.id }}" {% if s.id == xui_default_panel_id %}selected{% endif %}>{{ s.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-hint">{{ _('xui_server_select_hint') }}</div>
|
||||
<label class="form-label" style="margin-top:var(--space-sm);">{{ _('xui_inbound_label') }}</label>
|
||||
<select class="form-select" id="ucXuiInbound">
|
||||
<option value="">{{ _('invite_inbound_loading') }}</option>
|
||||
</select>
|
||||
<div class="form-hint">{{ _('xui_inbound_hint') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="ucNameGroup">
|
||||
@@ -639,14 +643,42 @@
|
||||
}
|
||||
|
||||
async function loadXuiInbounds() {
|
||||
// Inbound is assigned by the selected 3x-ui panel — nothing to load here.
|
||||
const select = document.getElementById('ucXuiInbound');
|
||||
if (!select) return;
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_loading')}</option>`;
|
||||
try {
|
||||
const panelId = document.getElementById('ucXuiPanel')?.value || '';
|
||||
const q = panelId ? `?panel_id=${encodeURIComponent(panelId)}` : '';
|
||||
const data = await apiCall('/api/settings/xui/inbounds' + q);
|
||||
const list = data.inbounds || [];
|
||||
if (!list.length) {
|
||||
select.innerHTML = `<option value="">${_('invite_inbound_empty')}</option>`;
|
||||
return;
|
||||
}
|
||||
select.innerHTML = '';
|
||||
list.forEach((ib, idx) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = ib.id;
|
||||
opt.textContent = `${ib.remark || 'VLESS'} (:${ib.port})`;
|
||||
if (xuiDefaultInboundId && String(ib.id) === String(xuiDefaultInboundId)) opt.selected = true;
|
||||
else if (!xuiDefaultInboundId && idx === 0) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
} catch (err) {
|
||||
select.innerHTML = `<option value="">${_('error')}: ${err.message}</option>`;
|
||||
}
|
||||
}
|
||||
|
||||
function updateXuiInboundVisibility() {
|
||||
const proto = document.getElementById('ucProtocol')?.value;
|
||||
const group = document.getElementById('ucXuiInboundGroup');
|
||||
if (!group) return;
|
||||
group.style.display = (proto === 'xui') ? 'block' : 'none';
|
||||
if (proto === 'xui') {
|
||||
group.style.display = 'block';
|
||||
loadXuiInbounds();
|
||||
} else {
|
||||
group.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Show/hide connection fields
|
||||
@@ -847,6 +879,9 @@
|
||||
if (!clientId) throw new Error(_('select_connection'));
|
||||
body.client_id = clientId;
|
||||
} else if (body.protocol === 'xui') {
|
||||
const inbound = parseInt(document.getElementById('ucXuiInbound').value || '0');
|
||||
if (!inbound) throw new Error(_('invite_inbound_required'));
|
||||
body.xui_inbound_id = inbound;
|
||||
body.xui_panel_id = document.getElementById('ucXuiPanel')?.value || '';
|
||||
} else if (body.protocol === 'telemt') {
|
||||
body.telemt_quota = document.getElementById('ucTelemtQuota').value || null;
|
||||
|
||||
Reference in New Issue
Block a user