mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 17:46:02 +00:00
refactor(inbounds): reorder Inbound's Data tabs (client first, sub inline)
Some checks are pending
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (push) Waiting to run
Some checks are pending
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (push) Waiting to run
Show the per-client pane as the default tab and fold the subscription URLs into its bottom (under a divider) so the modal has two tabs instead of three. Inbound details move to the second tab and remain the default fallback for protocol-only entries (HTTP/Mixed/Tunnel/ WireGuard) that have no per-client view.
This commit is contained in:
parent
5ac88271af
commit
267fb1c866
1 changed files with 210 additions and 208 deletions
|
|
@ -180,8 +180,7 @@ function downloadText(content, filename) {
|
||||||
FileManager.downloadTextFile(content, filename);
|
FileManager.downloadTextFile(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active tab in the 3-pane layout. Reset on each open below.
|
const activeTab = ref('client');
|
||||||
const activeTab = ref('inbound');
|
|
||||||
|
|
||||||
// === Build state on open ===========================================
|
// === Build state on open ===========================================
|
||||||
function genSubLink(subId) {
|
function genSubLink(subId) {
|
||||||
|
|
@ -195,7 +194,7 @@ watch(() => props.open, (next) => {
|
||||||
if (!next) return;
|
if (!next) return;
|
||||||
if (!props.dbInbound) return;
|
if (!props.dbInbound) return;
|
||||||
|
|
||||||
activeTab.value = 'inbound';
|
activeTab.value = props.dbInbound.toInbound().clients?.length ? 'client' : 'inbound';
|
||||||
dbInbound.value = props.dbInbound;
|
dbInbound.value = props.dbInbound;
|
||||||
inbound.value = props.dbInbound.toInbound();
|
inbound.value = props.dbInbound.toInbound();
|
||||||
|
|
||||||
|
|
@ -272,7 +271,214 @@ const showSubscriptionTab = computed(
|
||||||
<template v-if="dbInbound && inbound">
|
<template v-if="dbInbound && inbound">
|
||||||
<a-tabs v-model:active-key="activeTab">
|
<a-tabs v-model:active-key="activeTab">
|
||||||
<!-- ============================================================
|
<!-- ============================================================
|
||||||
TAB 1 — Inbound: protocol, transport, security, per-protocol
|
TAB 1 — Client: per-client info + share links + subscription
|
||||||
|
(subscription is folded in here so users don't need a third
|
||||||
|
tab — the sub URLs are per-client anyway).
|
||||||
|
============================================================== -->
|
||||||
|
<a-tab-pane v-if="showClientTab" key="client" :tab="t('pages.inbounds.client')">
|
||||||
|
<table class="info-table block">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>{{ t('pages.inbounds.email') }}</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientSettings.email" color="green">{{ clientSettings.email }}</a-tag>
|
||||||
|
<a-tag v-else color="red">{{ t('none') }}</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="clientSettings.id">
|
||||||
|
<td>ID</td>
|
||||||
|
<td><a-tag>{{ clientSettings.id }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="dbInbound.isVMess">
|
||||||
|
<td>{{ t('security') }}</td>
|
||||||
|
<td><a-tag>{{ clientSettings.security }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="inbound.canEnableTlsFlow()">
|
||||||
|
<td>Flow</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientSettings.flow">{{ clientSettings.flow }}</a-tag>
|
||||||
|
<a-tag v-else color="orange">{{ t('none') }}</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="clientSettings.password">
|
||||||
|
<td>{{ t('password') }}</td>
|
||||||
|
<td><a-tag class="info-large-tag">{{ clientSettings.password }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ t('status') }}</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="isDepleted" color="red">{{ t('depleted') }}</a-tag>
|
||||||
|
<a-tag v-else-if="isEnable" color="green">{{ t('enabled') }}</a-tag>
|
||||||
|
<a-tag v-else>{{ t('disabled') }}</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="clientStats">
|
||||||
|
<td>{{ t('usage') }}</td>
|
||||||
|
<td>
|
||||||
|
<a-tag color="green">
|
||||||
|
{{ SizeFormatter.sizeFormat(clientStats.up + clientStats.down) }}
|
||||||
|
</a-tag>
|
||||||
|
<a-tag>
|
||||||
|
↑ {{ SizeFormatter.sizeFormat(clientStats.up) }} /
|
||||||
|
{{ SizeFormatter.sizeFormat(clientStats.down) }} ↓
|
||||||
|
</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ t('pages.inbounds.createdAt') }}</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientSettings.created_at">{{ IntlUtil.formatDate(clientSettings.created_at, datepicker) }}</a-tag>
|
||||||
|
<a-tag v-else>-</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ t('pages.inbounds.updatedAt') }}</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientSettings.updated_at">{{ IntlUtil.formatDate(clientSettings.updated_at, datepicker) }}</a-tag>
|
||||||
|
<a-tag v-else>-</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ t('lastOnline') }}</td>
|
||||||
|
<td><a-tag>{{ formatLastOnline(clientSettings.email || '') }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="clientSettings.comment">
|
||||||
|
<td>{{ t('comment') }}</td>
|
||||||
|
<td><a-tag class="info-large-tag">{{ clientSettings.comment }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="ipLimitEnable">
|
||||||
|
<td>{{ t('pages.inbounds.IPLimit') }}</td>
|
||||||
|
<td><a-tag>{{ clientSettings.limitIp }}</a-tag></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="ipLimitEnable && clientSettings.limitIp > 0">
|
||||||
|
<td>{{ t('pages.inbounds.IPLimitlog') }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="ip-log">
|
||||||
|
<div v-if="clientIpsArray.length > 0">
|
||||||
|
<a-tag v-for="(item, idx) in clientIpsArray" :key="idx" color="blue" class="ip-log-row">{{ item
|
||||||
|
}}</a-tag>
|
||||||
|
</div>
|
||||||
|
<a-tag v-else>{{ clientIpsText || t('tgbot.noIpRecord') }}</a-tag>
|
||||||
|
</div>
|
||||||
|
<div class="ip-log-actions">
|
||||||
|
<SyncOutlined :spin="refreshing" @click="loadClientIps" />
|
||||||
|
<a-tooltip :title="t('pages.inbounds.IPLimitlogclear')">
|
||||||
|
<DeleteOutlined @click="clearClientIps" />
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Remaining / total / expiry -->
|
||||||
|
<table class="info-table summary-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ t('remained') }}</th>
|
||||||
|
<th>{{ t('pages.inbounds.totalUsage') }}</th>
|
||||||
|
<th>{{ t('pages.inbounds.expireDate') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientStats && clientSettings.totalGB > 0" :color="statsColor(clientStats)">{{
|
||||||
|
getRemainingStats() }}</a-tag>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientSettings.totalGB > 0" :color="clientStats ? statsColor(clientStats) : 'default'">{{
|
||||||
|
SizeFormatter.sizeFormat(clientSettings.totalGB) }}</a-tag>
|
||||||
|
<a-tag v-else color="purple">
|
||||||
|
<InfinityIcon />
|
||||||
|
</a-tag>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a-tag v-if="clientSettings.expiryTime > 0"
|
||||||
|
:color="ColorUtils.usageColor(Date.now(), expireDiff, clientSettings.expiryTime)">{{
|
||||||
|
IntlUtil.formatDate(clientSettings.expiryTime, datepicker) }}</a-tag>
|
||||||
|
<a-tag v-else-if="clientSettings.expiryTime < 0" color="green">
|
||||||
|
{{ clientSettings.expiryTime / -86400000 }} {{ t('day') }}
|
||||||
|
</a-tag>
|
||||||
|
<a-tag v-else color="purple">
|
||||||
|
<InfinityIcon />
|
||||||
|
</a-tag>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Telegram chat id -->
|
||||||
|
<template v-if="tgBotEnable && clientSettings.tgId">
|
||||||
|
<a-divider>Telegram</a-divider>
|
||||||
|
<div class="tg-row">
|
||||||
|
<a-tag color="blue">{{ clientSettings.tgId }}</a-tag>
|
||||||
|
<a-tooltip :title="t('copy')">
|
||||||
|
<a-button size="small" @click="copyText(clientSettings.tgId)">
|
||||||
|
<template #icon>
|
||||||
|
<CopyOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Per-client share links (no QR) -->
|
||||||
|
<template v-if="dbInbound.hasLink() && links.length > 0">
|
||||||
|
<a-divider>{{ t('pages.inbounds.copyLink') }}</a-divider>
|
||||||
|
<div v-for="(link, idx) in links" :key="idx" class="link-panel">
|
||||||
|
<div class="link-panel-header">
|
||||||
|
<a-tag color="green">{{ link.remark || `Link ${idx + 1}` }}</a-tag>
|
||||||
|
<a-tooltip :title="t('copy')">
|
||||||
|
<a-button size="small" @click="copyText(link.link)">
|
||||||
|
<template #icon>
|
||||||
|
<CopyOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<code class="link-panel-text">{{ link.link }}</code>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Subscription URLs — folded into the client tab so they sit
|
||||||
|
with the rest of the per-client data. Only visible when
|
||||||
|
subscriptions are enabled and this client has a subId. -->
|
||||||
|
<template v-if="showSubscriptionTab">
|
||||||
|
<a-divider>{{ t('subscription.title') }}</a-divider>
|
||||||
|
<div class="link-panel">
|
||||||
|
<div class="link-panel-header">
|
||||||
|
<a-tag color="green">{{ t('subscription.title') }}</a-tag>
|
||||||
|
<a-tooltip :title="t('copy')">
|
||||||
|
<a-button size="small" @click="copyText(subLink)">
|
||||||
|
<template #icon>
|
||||||
|
<CopyOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<a :href="subLink" target="_blank" rel="noopener noreferrer" class="link-panel-anchor">{{ subLink }}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="subSettings.subJsonEnable && subJsonLink" class="link-panel">
|
||||||
|
<div class="link-panel-header">
|
||||||
|
<a-tag color="green">JSON</a-tag>
|
||||||
|
<a-tooltip :title="t('copy')">
|
||||||
|
<a-button size="small" @click="copyText(subJsonLink)">
|
||||||
|
<template #icon>
|
||||||
|
<CopyOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<a :href="subJsonLink" target="_blank" rel="noopener noreferrer" class="link-panel-anchor">{{ subJsonLink
|
||||||
|
}}</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-tab-pane>
|
||||||
|
|
||||||
|
<!-- ============================================================
|
||||||
|
TAB 2 — Inbound: protocol, transport, security, per-protocol
|
||||||
============================================================== -->
|
============================================================== -->
|
||||||
<a-tab-pane key="inbound" :tab="t('pages.xray.rules.inbound')">
|
<a-tab-pane key="inbound" :tab="t('pages.xray.rules.inbound')">
|
||||||
<dl class="info-list">
|
<dl class="info-list">
|
||||||
|
|
@ -572,210 +778,6 @@ const showSubscriptionTab = computed(
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
|
||||||
<!-- ============================================================
|
|
||||||
TAB 2 — Client: per-client info + share links (no QR)
|
|
||||||
============================================================== -->
|
|
||||||
<a-tab-pane v-if="showClientTab" key="client" :tab="t('pages.inbounds.client')">
|
|
||||||
<table class="info-table block">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{ t('pages.inbounds.email') }}</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientSettings.email" color="green">{{ clientSettings.email }}</a-tag>
|
|
||||||
<a-tag v-else color="red">{{ t('none') }}</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="clientSettings.id">
|
|
||||||
<td>ID</td>
|
|
||||||
<td><a-tag>{{ clientSettings.id }}</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="dbInbound.isVMess">
|
|
||||||
<td>{{ t('security') }}</td>
|
|
||||||
<td><a-tag>{{ clientSettings.security }}</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="inbound.canEnableTlsFlow()">
|
|
||||||
<td>Flow</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientSettings.flow">{{ clientSettings.flow }}</a-tag>
|
|
||||||
<a-tag v-else color="orange">{{ t('none') }}</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="clientSettings.password">
|
|
||||||
<td>{{ t('password') }}</td>
|
|
||||||
<td><a-tag class="info-large-tag">{{ clientSettings.password }}</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ t('status') }}</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="isDepleted" color="red">{{ t('depleted') }}</a-tag>
|
|
||||||
<a-tag v-else-if="isEnable" color="green">{{ t('enabled') }}</a-tag>
|
|
||||||
<a-tag v-else>{{ t('disabled') }}</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="clientStats">
|
|
||||||
<td>{{ t('usage') }}</td>
|
|
||||||
<td>
|
|
||||||
<a-tag color="green">
|
|
||||||
{{ SizeFormatter.sizeFormat(clientStats.up + clientStats.down) }}
|
|
||||||
</a-tag>
|
|
||||||
<a-tag>
|
|
||||||
↑ {{ SizeFormatter.sizeFormat(clientStats.up) }} /
|
|
||||||
{{ SizeFormatter.sizeFormat(clientStats.down) }} ↓
|
|
||||||
</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ t('pages.inbounds.createdAt') }}</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientSettings.created_at">{{ IntlUtil.formatDate(clientSettings.created_at, datepicker) }}</a-tag>
|
|
||||||
<a-tag v-else>-</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ t('pages.inbounds.updatedAt') }}</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientSettings.updated_at">{{ IntlUtil.formatDate(clientSettings.updated_at, datepicker) }}</a-tag>
|
|
||||||
<a-tag v-else>-</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ t('lastOnline') }}</td>
|
|
||||||
<td><a-tag>{{ formatLastOnline(clientSettings.email || '') }}</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="clientSettings.comment">
|
|
||||||
<td>{{ t('comment') }}</td>
|
|
||||||
<td><a-tag class="info-large-tag">{{ clientSettings.comment }}</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="ipLimitEnable">
|
|
||||||
<td>{{ t('pages.inbounds.IPLimit') }}</td>
|
|
||||||
<td><a-tag>{{ clientSettings.limitIp }}</a-tag></td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="ipLimitEnable && clientSettings.limitIp > 0">
|
|
||||||
<td>{{ t('pages.inbounds.IPLimitlog') }}</td>
|
|
||||||
<td>
|
|
||||||
<div class="ip-log">
|
|
||||||
<div v-if="clientIpsArray.length > 0">
|
|
||||||
<a-tag v-for="(item, idx) in clientIpsArray" :key="idx" color="blue" class="ip-log-row">{{ item
|
|
||||||
}}</a-tag>
|
|
||||||
</div>
|
|
||||||
<a-tag v-else>{{ clientIpsText || t('tgbot.noIpRecord') }}</a-tag>
|
|
||||||
</div>
|
|
||||||
<div class="ip-log-actions">
|
|
||||||
<SyncOutlined :spin="refreshing" @click="loadClientIps" />
|
|
||||||
<a-tooltip :title="t('pages.inbounds.IPLimitlogclear')">
|
|
||||||
<DeleteOutlined @click="clearClientIps" />
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- Remaining / total / expiry -->
|
|
||||||
<table class="info-table summary-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{{ t('remained') }}</th>
|
|
||||||
<th>{{ t('pages.inbounds.totalUsage') }}</th>
|
|
||||||
<th>{{ t('pages.inbounds.expireDate') }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientStats && clientSettings.totalGB > 0" :color="statsColor(clientStats)">{{
|
|
||||||
getRemainingStats() }}</a-tag>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientSettings.totalGB > 0" :color="clientStats ? statsColor(clientStats) : 'default'">{{
|
|
||||||
SizeFormatter.sizeFormat(clientSettings.totalGB) }}</a-tag>
|
|
||||||
<a-tag v-else color="purple">
|
|
||||||
<InfinityIcon />
|
|
||||||
</a-tag>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a-tag v-if="clientSettings.expiryTime > 0"
|
|
||||||
:color="ColorUtils.usageColor(Date.now(), expireDiff, clientSettings.expiryTime)">{{
|
|
||||||
IntlUtil.formatDate(clientSettings.expiryTime, datepicker) }}</a-tag>
|
|
||||||
<a-tag v-else-if="clientSettings.expiryTime < 0" color="green">
|
|
||||||
{{ clientSettings.expiryTime / -86400000 }} {{ t('day') }}
|
|
||||||
</a-tag>
|
|
||||||
<a-tag v-else color="purple">
|
|
||||||
<InfinityIcon />
|
|
||||||
</a-tag>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- Telegram chat id -->
|
|
||||||
<template v-if="tgBotEnable && clientSettings.tgId">
|
|
||||||
<a-divider>Telegram</a-divider>
|
|
||||||
<div class="tg-row">
|
|
||||||
<a-tag color="blue">{{ clientSettings.tgId }}</a-tag>
|
|
||||||
<a-tooltip :title="t('copy')">
|
|
||||||
<a-button size="small" @click="copyText(clientSettings.tgId)">
|
|
||||||
<template #icon>
|
|
||||||
<CopyOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- Per-client share links (no QR) -->
|
|
||||||
<template v-if="dbInbound.hasLink() && links.length > 0">
|
|
||||||
<a-divider>{{ t('pages.inbounds.copyLink') }}</a-divider>
|
|
||||||
<div v-for="(link, idx) in links" :key="idx" class="link-panel">
|
|
||||||
<div class="link-panel-header">
|
|
||||||
<a-tag color="green">{{ link.remark || `Link ${idx + 1}` }}</a-tag>
|
|
||||||
<a-tooltip :title="t('copy')">
|
|
||||||
<a-button size="small" @click="copyText(link.link)">
|
|
||||||
<template #icon>
|
|
||||||
<CopyOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
<code class="link-panel-text">{{ link.link }}</code>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<!-- ============================================================
|
|
||||||
TAB 3 — Subscription: clickable subscription URLs
|
|
||||||
============================================================== -->
|
|
||||||
<a-tab-pane v-if="showSubscriptionTab" key="subscription" :tab="t('subscription.title')">
|
|
||||||
<div class="link-panel">
|
|
||||||
<div class="link-panel-header">
|
|
||||||
<a-tag color="green">{{ t('subscription.title') }}</a-tag>
|
|
||||||
<a-tooltip :title="t('copy')">
|
|
||||||
<a-button size="small" @click="copyText(subLink)">
|
|
||||||
<template #icon>
|
|
||||||
<CopyOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
<a :href="subLink" target="_blank" rel="noopener noreferrer" class="link-panel-anchor">{{ subLink }}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="subSettings.subJsonEnable && subJsonLink" class="link-panel">
|
|
||||||
<div class="link-panel-header">
|
|
||||||
<a-tag color="green">JSON</a-tag>
|
|
||||||
<a-tooltip :title="t('copy')">
|
|
||||||
<a-button size="small" @click="copyText(subJsonLink)">
|
|
||||||
<template #icon>
|
|
||||||
<CopyOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
<a :href="subJsonLink" target="_blank" rel="noopener noreferrer" class="link-panel-anchor">{{ subJsonLink
|
|
||||||
}}</a>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</template>
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue