feat(inbounds): bulk-select clients + UX polish

- ClientBulkModal: add `comment` and VLESS `reverseTag` fields so the
  bulk-add modal can set them on every generated client (matching the
  single-client form)
- ClientRowTable: add multi-select checkboxes (desktop + mobile) with a
  tri-state select-all and a sticky bulk-action bar; emits a new
  `delete-clients` event so the parent can wipe the picked clients in
  one go. Hidden entirely when the inbound has only one client (the
  last one must stay)
- ClientRowTable: new "Remained" column shows live remaining quota
  per client (∞ for unlimited, red when depleted)
- InboundInfoModal: Remained cell now shows the ∞ tag when the client
  has no totalGB limit, matching how Total Usage already renders it
- InboundsPage: add Online tag (+ per-bucket popovers listing client
  emails) to the summary card so it mirrors the per-inbound row, and
  wire an `onDeleteClients` handler that loops the existing single-
  delete endpoint then refreshes once
- InboundList: forward the `delete-clients` event; hide empty remarks
  on both the desktop table (custom #bodyCell) and the mobile card
- useInbounds: aggregate an `online` email list across all inbounds
  so the summary popover has data to render
This commit is contained in:
MHSanaei
2026-05-11 03:50:28 +02:00
parent e4900f1bd4
commit 6d732d8d32
6 changed files with 231 additions and 14 deletions
+3 -1
View File
@@ -287,6 +287,7 @@ export function useInbounds() {
const deactive = [];
const depleted = [];
const expiring = [];
const online = [];
for (const ib of dbInbounds.value) {
up += ib.up || 0;
down += ib.down || 0;
@@ -297,9 +298,10 @@ export function useInbounds() {
deactive.push(...c.deactive);
depleted.push(...c.depleted);
expiring.push(...c.expiring);
online.push(...c.online);
}
}
return { up, down, allTime, clients, deactive, depleted, expiring };
return { up, down, allTime, clients, deactive, depleted, expiring, online };
});
// ObjectUtil reference is wired at module load — keeping a no-op import