diff --git a/frontend/src/pages/inbounds/InboundInfoModal.vue b/frontend/src/pages/inbounds/InboundInfoModal.vue new file mode 100644 index 00000000..6611bbce --- /dev/null +++ b/frontend/src/pages/inbounds/InboundInfoModal.vue @@ -0,0 +1,768 @@ + + + + + diff --git a/frontend/src/pages/inbounds/InboundsPage.vue b/frontend/src/pages/inbounds/InboundsPage.vue index c951091a..6c0d3b4c 100644 --- a/frontend/src/pages/inbounds/InboundsPage.vue +++ b/frontend/src/pages/inbounds/InboundsPage.vue @@ -19,6 +19,8 @@ import InboundList from './InboundList.vue'; import InboundFormModal from './InboundFormModal.vue'; import ClientFormModal from './ClientFormModal.vue'; import ClientBulkModal from './ClientBulkModal.vue'; +import InboundInfoModal from './InboundInfoModal.vue'; +import QrCodeModal from './QrCodeModal.vue'; import { useInbounds } from './useInbounds.js'; const antdThemeConfig = computed(() => ({ @@ -38,6 +40,8 @@ const { subSettings, tgBotEnable, ipLimitEnable, + remarkModel, + lastOnlineMap, refresh, fetchDefaultSettings, } = useInbounds(); @@ -65,6 +69,54 @@ const clientIndex = ref(null); const bulkOpen = ref(false); const bulkDbInbound = ref(null); +// === Info / QR-code modals =========================================== +const infoOpen = ref(false); +const infoDbInbound = ref(null); +const infoClientIndex = ref(0); + +const qrOpen = ref(false); +const qrDbInbound = ref(null); + +// `checkFallback` mirrors the legacy helper: when an inbound listens +// on a unix-socket fallback (`@`), point the link generator at +// the root inbound that owns the listen address so QRs/links carry +// the externally-reachable host:port and the right TLS state. +function checkFallback(dbInbound) { + // We don't keep parsed Inbounds in state right now (the page works + // off DBInbounds); compute on the fly. + if (!dbInbound.listen?.startsWith?.('@')) return dbInbound; + for (const candidate of dbInbounds.value) { + if (candidate.id === dbInbound.id) continue; + const parsed = candidate.toInbound(); + if (!parsed.isTcp) continue; + if (!['trojan', 'vless'].includes(parsed.protocol)) continue; + const fallbacks = parsed.settings.fallbacks || []; + if (!fallbacks.find((f) => f.dest === dbInbound.listen)) continue; + // Build a one-off DBInbound copy with the parent's listen/port + + // copied stream so the link gen sees the public endpoint. + const projected = JSON.parse(JSON.stringify(dbInbound)); + projected.listen = candidate.listen; + projected.port = candidate.port; + const inheritedStream = parsed.stream; + const ownInbound = dbInbound.toInbound(); + ownInbound.stream.security = inheritedStream.security; + ownInbound.stream.tls = inheritedStream.tls; + ownInbound.stream.externalProxy = inheritedStream.externalProxy; + projected.streamSettings = ownInbound.stream.toString(); + // Re-wrap so callers get the same DBInbound shape they had. + return new dbInbound.constructor(projected); + } + return dbInbound; +} + +function findClientIndex(dbInbound) { + // For now we always show client 0 — multi-client navigation lives + // in the per-inbound expand-row table (5f-vi). A future commit will + // route client.email through this helper. + void dbInbound; + return 0; +} + function onAddInbound() { formMode.value = 'add'; formDbInbound.value = null; @@ -204,6 +256,15 @@ function onRowAction({ key, dbInbound }) { case 'addBulkClient': openAddBulkClient(dbInbound); break; + case 'showInfo': + infoDbInbound.value = checkFallback(dbInbound); + infoClientIndex.value = findClientIndex(dbInbound); + infoOpen.value = true; + break; + case 'qrcode': + qrDbInbound.value = checkFallback(dbInbound); + qrOpen.value = true; + break; case 'delete': confirmDelete(dbInbound); break; @@ -345,6 +406,23 @@ function onRowAction({ key, dbInbound }) { :ip-limit-enable="ipLimitEnable" @saved="refresh" /> + + diff --git a/frontend/src/pages/inbounds/QrCodeModal.vue b/frontend/src/pages/inbounds/QrCodeModal.vue new file mode 100644 index 00000000..9eddb7be --- /dev/null +++ b/frontend/src/pages/inbounds/QrCodeModal.vue @@ -0,0 +1,68 @@ + + + diff --git a/frontend/src/pages/inbounds/QrPanel.vue b/frontend/src/pages/inbounds/QrPanel.vue new file mode 100644 index 00000000..2773c92a --- /dev/null +++ b/frontend/src/pages/inbounds/QrPanel.vue @@ -0,0 +1,128 @@ + + + + +