Template
Add 3x-ui VLESS configs and guest access without registration.
Guests can open a public link to view or create VPN configs; panel creates VLESS clients via the 3x-ui API. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+60
-10
@@ -291,6 +291,14 @@
|
||||
<div class="form-hint">{{ _('existing_conn_hint') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="ucXuiInboundGroup" style="display:none;">
|
||||
<label class="form-label">{{ _('xui_inbound_label') }}</label>
|
||||
<select class="form-select" id="ucXuiInbound">
|
||||
<option value="">{{ _('xui_inbound_auto') }}</option>
|
||||
</select>
|
||||
<div class="form-hint">{{ _('xui_inbound_hint') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="ucNameGroup">
|
||||
<label class="form-label">{{ _('conn_name_panel') }}</label>
|
||||
<input class="form-input" type="text" id="ucName" placeholder="{{ _('connection_name_placeholder') }}">
|
||||
@@ -397,6 +405,8 @@
|
||||
let searchTimeout = null;
|
||||
|
||||
const serversData = {{ servers | tojson }};
|
||||
const xuiConfigured = {{ 'true' if xui_configured else 'false' }};
|
||||
const xuiDefaultInboundId = {{ xui_inbound_id | int }};
|
||||
|
||||
function populateTimeSelect(selectId) {
|
||||
const select = document.getElementById(selectId);
|
||||
@@ -587,16 +597,11 @@
|
||||
const group = groupId ? document.getElementById(groupId) : null;
|
||||
select.innerHTML = '';
|
||||
const vpnBases = new Set(['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'wireguard']);
|
||||
|
||||
if (serverId === '') {
|
||||
if (group) group.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const server = serversData[serverId];
|
||||
const protocols = server.protocols || {};
|
||||
let count = 0;
|
||||
|
||||
const server = (serverId !== '' && serversData[serverId]) ? serversData[serverId] : null;
|
||||
const protocols = (server && server.protocols) || {};
|
||||
|
||||
for (const [key, info] of Object.entries(protocols)) {
|
||||
if (!info.installed) continue;
|
||||
const base = key.split('__')[0];
|
||||
@@ -608,6 +613,14 @@
|
||||
count++;
|
||||
}
|
||||
|
||||
if (xuiConfigured && selectId === 'ucProtocol') {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = 'xui';
|
||||
opt.textContent = '3x-ui VLESS';
|
||||
select.appendChild(opt);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
if (group) group.style.display = '';
|
||||
} else {
|
||||
@@ -617,6 +630,39 @@
|
||||
select.appendChild(opt);
|
||||
if (group) group.style.display = '';
|
||||
}
|
||||
if (selectId === 'ucProtocol') {
|
||||
updateXuiInboundVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
async function loadXuiInbounds() {
|
||||
const select = document.getElementById('ucXuiInbound');
|
||||
if (!select) return;
|
||||
select.innerHTML = `<option value="">${_('xui_inbound_auto')}</option>`;
|
||||
try {
|
||||
const data = await apiCall('/api/settings/xui/inbounds');
|
||||
(data.inbounds || []).forEach(ib => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = ib.id;
|
||||
opt.textContent = `${ib.remark || 'VLESS'} (:${ib.port})`;
|
||||
if (String(ib.id) === String(xuiDefaultInboundId)) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
} catch (err) {
|
||||
showToast(`${_('error')}: ${err.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function updateXuiInboundVisibility() {
|
||||
const proto = document.getElementById('ucProtocol')?.value;
|
||||
const group = document.getElementById('ucXuiInboundGroup');
|
||||
if (!group) return;
|
||||
if (proto === 'xui') {
|
||||
group.style.display = 'block';
|
||||
loadXuiInbounds();
|
||||
} else {
|
||||
group.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Show/hide connection fields
|
||||
@@ -649,6 +695,7 @@
|
||||
fetchExistingClients();
|
||||
}
|
||||
updateTelemtOptions('ucProtocol', 'ucTelemtOptions');
|
||||
updateXuiInboundVisibility();
|
||||
});
|
||||
|
||||
async function addUser(e) {
|
||||
@@ -806,7 +853,7 @@
|
||||
|
||||
try {
|
||||
const body = {
|
||||
server_id: parseInt(document.getElementById('ucServer').value),
|
||||
server_id: parseInt(document.getElementById('ucServer').value) || 0,
|
||||
protocol: document.getElementById('ucProtocol').value,
|
||||
name: document.getElementById('ucName').value || 'VPN Connection',
|
||||
};
|
||||
@@ -815,6 +862,9 @@
|
||||
const clientId = document.getElementById('ucExistingClient').value;
|
||||
if (!clientId) throw new Error(_('select_connection'));
|
||||
body.client_id = clientId;
|
||||
} else if (body.protocol === 'xui') {
|
||||
const inbound = document.getElementById('ucXuiInbound').value;
|
||||
if (inbound) body.xui_inbound_id = parseInt(inbound);
|
||||
} else if (body.protocol === 'telemt') {
|
||||
body.telemt_quota = document.getElementById('ucTelemtQuota').value || null;
|
||||
body.telemt_max_ips = parseInt(document.getElementById('ucTelemtMaxIps').value) || null;
|
||||
@@ -870,7 +920,7 @@
|
||||
<div class="client-name">${c.name || 'Connection'}</div>
|
||||
<div class="client-meta">
|
||||
<span>🖥 ${c.server_name || ''}</span>
|
||||
<span>${c.protocol === 'awg' ? 'AmneziaWG' : (c.protocol === 'awg2' ? 'AmneziaWG 2.0' : (c.protocol === 'awg_legacy' ? 'AWG Legacy' : (c.protocol === 'xray' ? 'Xray' : c.protocol.toUpperCase())))}</span>
|
||||
<span>${c.protocol === 'awg' ? 'AmneziaWG' : (c.protocol === 'awg2' ? 'AmneziaWG 2.0' : (c.protocol === 'awg_legacy' ? 'AWG Legacy' : (c.protocol === 'xray' ? 'Xray' : (c.protocol === 'xui' ? '3x-ui VLESS' : c.protocol.toUpperCase()))))}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user