2026-05-08 11:52:45 +00:00
|
|
|
<script setup>
|
|
|
|
|
import { ref, watch } from 'vue';
|
2026-05-08 15:20:30 +00:00
|
|
|
import { useI18n } from 'vue-i18n';
|
2026-05-08 11:52:45 +00:00
|
|
|
|
build(frontend): bump eslint to 10 + add flat config + clean lint warnings
- Upgrade eslint 9.39 -> 10.3 and eslint-plugin-vue 9.33 -> 10.9
- Add eslint.config.js (flat config required by ESLint 10) with
vue3-recommended rules, sensible defaults, and exemptions for the
project's existing formatting style
- Drop --ext from the lint script (removed in ESLint 10)
- vue/no-mutating-props is left off because the form-modal pattern
ports straight from Vue 2 (parent passes a reactive object, child
mutates it); a real fix is an architectural rewire, separate task
Lint warning cleanup:
- utils/index.js: var -> let/const in the X25519 routines, replace
obj.hasOwnProperty(...) with Object.prototype.hasOwnProperty.call(...)
- Remove unused imports (reactive, ref, Inbound) in ClientFormModal,
InboundInfoModal, QrCodeModal, DnsServerModal, OutboundFormModal,
SubPage; remove unused locals (isClientOnline, ONLINE_GRACE_MS,
fetchAll, isSocks, isHTTP, _antdAlgorithm)
- XrayStatusCard: declare 'open-logs' on defineEmits (was emitted but
not declared)
- RuleFormModal: rename v-for var t -> tag (shadowed useI18n's t)
- Drop stale eslint-disable directives (no-new, no-unused-vars)
- OutboundsTab/InboundList: drop redundant initial null assigns
- InboundInfoModal/OutboundFormModal: explicit eslint-disable for the
intentional local-ref-shadows-prop pattern in modal drafts
`npm run lint` now passes with 0 errors and 0 warnings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 00:36:47 +00:00
|
|
|
import { Protocols } from '@/models/inbound.js';
|
2026-05-08 11:52:45 +00:00
|
|
|
import QrPanel from './QrPanel.vue';
|
|
|
|
|
|
2026-05-08 15:20:30 +00:00
|
|
|
const { t } = useI18n();
|
|
|
|
|
|
2026-05-08 11:52:45 +00:00
|
|
|
// Light QR-only modal — used for the "qrcode" row action on
|
|
|
|
|
// single-user Shadowsocks and WireGuard inbounds. The big info modal
|
|
|
|
|
// (InboundInfoModal) is too detailed when the user just wants the
|
|
|
|
|
// share link as a QR.
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
open: { type: Boolean, default: false },
|
|
|
|
|
dbInbound: { type: Object, default: null },
|
feat(frontend): inbound modal QR + tabs + restored TLS fallbacks
Per-client QR action: the qr icon on the expand-row table opened the
big info modal instead of the QR modal. Route it to QrCodeModal and
extend that modal with a `client` prop so genAllLinks() produces the
per-client share URLs (and per-peer remarks for WireGuard).
Inbound's Data redesign: split the dense single-page view into three
tabs — Inbound, Client, Subscription. Drop every QR rendering from
this modal (QrCodeModal is the QR home now). Each row in the Inbound
tab is one label/value pair instead of the legacy 2-column grid, and
long values like the VLESS encryption blob render as a wrapping code
block with a copy button so they can't blow out the dialog. The
Subscription tab renders sub URL + JSON URL as clickable anchors that
open in a new tab.
Restored TLS fallbacks UI: the model already exposed
VLESSSettings.Fallback / TrojanSettings.Fallback with addFallback /
delFallback / fallbackToJson, but the form modal never surfaced them
during the Vue 3 migration. Re-add the legacy form (SNI, ALPN, Path,
Destination, PROXY) on the protocol tab, gated on TCP transport plus
(for VLESS) encryption=none — same conditions as main.
Column widths: Protocol 70→130 and All-time Traffic 60→95 in the
inbound list; All-time Traffic 90→130 in the client expand-row, so
the header text fits and tags don't get squeezed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:45:14 +00:00
|
|
|
client: { type: Object, default: null },
|
2026-05-08 11:52:45 +00:00
|
|
|
remarkModel: { type: String, default: '-ieo' },
|
2026-05-09 13:25:29 +00:00
|
|
|
// Address of the node hosting this inbound (empty string for local).
|
|
|
|
|
// When set, share/QR links use it as the host instead of the panel's
|
|
|
|
|
// origin — node-managed inbounds proxy from the node, not the panel.
|
|
|
|
|
nodeAddress: { type: String, default: '' },
|
2026-05-08 11:52:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(['update:open']);
|
|
|
|
|
|
|
|
|
|
const links = ref([]);
|
|
|
|
|
const wireguardConfigs = ref([]);
|
|
|
|
|
const wireguardLinks = ref([]);
|
|
|
|
|
|
|
|
|
|
watch(() => props.open, (next) => {
|
|
|
|
|
if (!next || !props.dbInbound) return;
|
|
|
|
|
const inbound = props.dbInbound.toInbound();
|
|
|
|
|
if (inbound.protocol === Protocols.WIREGUARD) {
|
feat(frontend): inbound modal QR + tabs + restored TLS fallbacks
Per-client QR action: the qr icon on the expand-row table opened the
big info modal instead of the QR modal. Route it to QrCodeModal and
extend that modal with a `client` prop so genAllLinks() produces the
per-client share URLs (and per-peer remarks for WireGuard).
Inbound's Data redesign: split the dense single-page view into three
tabs — Inbound, Client, Subscription. Drop every QR rendering from
this modal (QrCodeModal is the QR home now). Each row in the Inbound
tab is one label/value pair instead of the legacy 2-column grid, and
long values like the VLESS encryption blob render as a wrapping code
block with a copy button so they can't blow out the dialog. The
Subscription tab renders sub URL + JSON URL as clickable anchors that
open in a new tab.
Restored TLS fallbacks UI: the model already exposed
VLESSSettings.Fallback / TrojanSettings.Fallback with addFallback /
delFallback / fallbackToJson, but the form modal never surfaced them
during the Vue 3 migration. Re-add the legacy form (SNI, ALPN, Path,
Destination, PROXY) on the protocol tab, gated on TCP transport plus
(for VLESS) encryption=none — same conditions as main.
Column widths: Protocol 70→130 and All-time Traffic 60→95 in the
inbound list; All-time Traffic 90→130 in the client expand-row, so
the header text fits and tags don't get squeezed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:45:14 +00:00
|
|
|
const peerRemark = props.client?.email
|
|
|
|
|
? `${props.dbInbound.remark}-${props.client.email}`
|
|
|
|
|
: props.dbInbound.remark;
|
2026-05-09 13:25:29 +00:00
|
|
|
wireguardConfigs.value = inbound.genWireguardConfigs(peerRemark, '-ieo', props.nodeAddress).split('\r\n');
|
|
|
|
|
wireguardLinks.value = inbound.genWireguardLinks(peerRemark, '-ieo', props.nodeAddress).split('\r\n');
|
2026-05-08 11:52:45 +00:00
|
|
|
links.value = [];
|
|
|
|
|
} else {
|
feat(frontend): inbound modal QR + tabs + restored TLS fallbacks
Per-client QR action: the qr icon on the expand-row table opened the
big info modal instead of the QR modal. Route it to QrCodeModal and
extend that modal with a `client` prop so genAllLinks() produces the
per-client share URLs (and per-peer remarks for WireGuard).
Inbound's Data redesign: split the dense single-page view into three
tabs — Inbound, Client, Subscription. Drop every QR rendering from
this modal (QrCodeModal is the QR home now). Each row in the Inbound
tab is one label/value pair instead of the legacy 2-column grid, and
long values like the VLESS encryption blob render as a wrapping code
block with a copy button so they can't blow out the dialog. The
Subscription tab renders sub URL + JSON URL as clickable anchors that
open in a new tab.
Restored TLS fallbacks UI: the model already exposed
VLESSSettings.Fallback / TrojanSettings.Fallback with addFallback /
delFallback / fallbackToJson, but the form modal never surfaced them
during the Vue 3 migration. Re-add the legacy form (SNI, ALPN, Path,
Destination, PROXY) on the protocol tab, gated on TCP transport plus
(for VLESS) encryption=none — same conditions as main.
Column widths: Protocol 70→130 and All-time Traffic 60→95 in the
inbound list; All-time Traffic 90→130 in the client expand-row, so
the header text fits and tags don't get squeezed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:45:14 +00:00
|
|
|
// When a client is provided we generate per-client share links;
|
|
|
|
|
// otherwise (single-user SS) fall back to the inbound's settings.
|
2026-05-09 13:25:29 +00:00
|
|
|
links.value = inbound.genAllLinks(props.dbInbound.remark, props.remarkModel, props.client, props.nodeAddress);
|
2026-05-08 11:52:45 +00:00
|
|
|
wireguardConfigs.value = [];
|
|
|
|
|
wireguardLinks.value = [];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function close() {
|
|
|
|
|
emit('update:open', false);
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2026-05-08 15:20:30 +00:00
|
|
|
<a-modal :open="open" :title="t('qrCode')" :footer="null" width="420px" @cancel="close">
|
2026-05-08 11:52:45 +00:00
|
|
|
<template v-if="dbInbound">
|
2026-05-08 19:05:14 +00:00
|
|
|
<QrPanel v-for="(link, idx) in links" :key="`l${idx}`" :value="link.link"
|
|
|
|
|
:remark="link.remark || `Link ${idx + 1}`" />
|
2026-05-08 11:52:45 +00:00
|
|
|
<template v-for="(cfg, idx) in wireguardConfigs" :key="`w${idx}`">
|
2026-05-08 19:05:14 +00:00
|
|
|
<QrPanel :value="cfg" :remark="`Peer ${idx + 1} config`" :download-name="`peer-${idx + 1}.conf`" />
|
|
|
|
|
<QrPanel v-if="wireguardLinks[idx]" :value="wireguardLinks[idx]" :remark="`Peer ${idx + 1} link`" />
|
2026-05-08 11:52:45 +00:00
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</a-modal>
|
|
|
|
|
</template>
|