mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-12 06:10:58 +00:00
feat(inbounds): collapse mobile cards to id/email + info button
Mobile inbound cards now show only #id and remark; mobile client cards show only the status badge and email. The full stat grid (protocol, port, node, traffic, all-time, clients, expiry — and per-client remained/online/expiry) moves behind a new info icon that opens an a-modal, so the list stays scannable on small screens.
This commit is contained in:
@@ -217,6 +217,14 @@ watch(clients, (list) => {
|
||||
if (next.size !== selected.value.size) selected.value = next;
|
||||
});
|
||||
|
||||
const statsClient = ref(null);
|
||||
function openStats(client) {
|
||||
statsClient.value = client;
|
||||
}
|
||||
function closeStats() {
|
||||
statsClient.value = null;
|
||||
}
|
||||
|
||||
function confirmBulkDelete() {
|
||||
const picked = clients.value.filter((c) => selected.value.has(rowKey(c)));
|
||||
if (picked.length === 0) return;
|
||||
@@ -433,6 +441,9 @@ function confirmBulkDelete() {
|
||||
<span class="client-email">{{ client.email }}</span>
|
||||
</a-tooltip>
|
||||
<div class="client-card-actions">
|
||||
<a-tooltip :title="t('info')">
|
||||
<InfoCircleOutlined class="row-icon" @click="openStats(client)" />
|
||||
</a-tooltip>
|
||||
<a-switch :checked="client.enable" size="small"
|
||||
@change="(next) => emit('toggle-enable-client', { dbInbound, client, next })" />
|
||||
<a-dropdown :trigger="['click']" placement="bottomRight">
|
||||
@@ -459,52 +470,55 @@ function confirmBulkDelete() {
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="client.comment && client.comment.trim()" class="client-comment-line">
|
||||
{{ client.comment.length > 80 ? client.comment.substring(0, 77) + '…' : client.comment }}
|
||||
</div>
|
||||
|
||||
<div class="client-card-foot">
|
||||
<a-modal :open="!!statsClient" :footer="null" :width="360" centered
|
||||
:title="statsClient ? statsClient.email || t('info') : ''" @cancel="closeStats">
|
||||
<div v-if="statsClient" class="client-card-foot">
|
||||
<div v-if="statsClient.comment && statsClient.comment.trim()" class="client-comment-line">
|
||||
{{ statsClient.comment }}
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">{{ t('pages.inbounds.traffic') }}</span>
|
||||
<a-tag :color="clientStatsColor(client.email)">
|
||||
{{ SizeFormatter.sizeFormat(getSum(client.email)) }} /
|
||||
<InfinityIcon v-if="isUnlimitedTotal(client)" />
|
||||
<template v-else>{{ totalGbDisplay(client) }}</template>
|
||||
<a-tag :color="clientStatsColor(statsClient.email)">
|
||||
{{ SizeFormatter.sizeFormat(getSum(statsClient.email)) }} /
|
||||
<InfinityIcon v-if="isUnlimitedTotal(statsClient)" />
|
||||
<template v-else>{{ totalGbDisplay(statsClient) }}</template>
|
||||
</a-tag>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">{{ t('remained') }}</span>
|
||||
<a-tag v-if="isUnlimitedTotal(client)" color="purple" :style="{ border: 'none' }" class="infinite-tag">
|
||||
<a-tag v-if="isUnlimitedTotal(statsClient)" color="purple" :style="{ border: 'none' }" class="infinite-tag">
|
||||
<InfinityIcon />
|
||||
</a-tag>
|
||||
<a-tag v-else :color="isClientDepleted(client.email) ? 'red' : ''">
|
||||
{{ SizeFormatter.sizeFormat(getRem(client.email)) }}
|
||||
<a-tag v-else :color="isClientDepleted(statsClient.email) ? 'red' : ''">
|
||||
{{ SizeFormatter.sizeFormat(getRem(statsClient.email)) }}
|
||||
</a-tag>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">{{ t('pages.inbounds.allTimeTraffic') }}</span>
|
||||
<a-tag>{{ SizeFormatter.sizeFormat(getAllTime(client.email)) }}</a-tag>
|
||||
<a-tag>{{ SizeFormatter.sizeFormat(getAllTime(statsClient.email)) }}</a-tag>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">{{ t('online') }}</span>
|
||||
<a-tag v-if="client.enable && isClientOnline(client.email)" color="green">{{ t('online') }}</a-tag>
|
||||
<a-tag v-if="statsClient.enable && isClientOnline(statsClient.email)" color="green">{{ t('online') }}</a-tag>
|
||||
<a-tag v-else>{{ t('offline') }}</a-tag>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">{{ t('pages.inbounds.expireDate') }}</span>
|
||||
<a-tag v-if="client.expiryTime > 0" :color="ColorUtils.userExpiryColor(expireDiff, client, isDarkTheme)">
|
||||
{{ IntlUtil.formatRelativeTime(client.expiryTime) }}
|
||||
<a-tag v-if="statsClient.expiryTime > 0"
|
||||
:color="ColorUtils.userExpiryColor(expireDiff, statsClient, isDarkTheme)">
|
||||
{{ IntlUtil.formatRelativeTime(statsClient.expiryTime) }}
|
||||
</a-tag>
|
||||
<a-tag v-else-if="client.expiryTime < 0" color="green">
|
||||
{{ -client.expiryTime / 86400000 }}d ({{ t('pages.client.delayedStart') }})
|
||||
<a-tag v-else-if="statsClient.expiryTime < 0" color="green">
|
||||
{{ -statsClient.expiryTime / 86400000 }}d ({{ t('pages.client.delayedStart') }})
|
||||
</a-tag>
|
||||
<a-tag v-else color="purple">
|
||||
<InfinityIcon />
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<a-pagination v-if="pageSize > 0 && clients.length > pageSize" v-model:current="currentPage"
|
||||
|
||||
Reference in New Issue
Block a user