diff --git a/public/userarea/filter_records.php b/public/userarea/filter_records.php
index 2ed5565..6c47bda 100644
--- a/public/userarea/filter_records.php
+++ b/public/userarea/filter_records.php
@@ -28,6 +28,60 @@ $wantAllIds = !empty($body['want_all_ids']);
$cacheDir = __DIR__ . '/cache';
+$explicitIds = [];
+if (isset($body['ids']) && is_array($body['ids'])) {
+ $explicitIds = array_values(array_unique(array_filter(
+ array_map('intval', $body['ids']),
+ fn($v) => $v > 0
+ )));
+}
+if (!empty($explicitIds)) {
+ // Scoping di sicurezza: solo record del template/utente/import corretti.
+ $conds = ['d.templateid = ?', 'd.status = ?'];
+ $params = [$templateId, $status];
+ if (!$showAll) { $conds[] = 'd.user_id = ?'; $params[] = $userId; }
+ if ($importref !== '') { $conds[] = 'd.importreferencecode = ?'; $params[] = $importref; }
+ $ph = implode(',', array_fill(0, count($explicitIds), '?'));
+ $conds[] = "d.iddatadb IN ($ph)";
+ foreach ($explicitIds as $id) $params[] = $id;
+ $whereSql = implode(' AND ', $conds);
+
+ try {
+ $countStmt = $pdo->prepare("SELECT COUNT(*) FROM datadb d WHERE {$whereSql}");
+ $countStmt->execute($params);
+ $total = (int)$countStmt->fetchColumn();
+ $totalPages = max(1, (int)ceil($total / $perPage));
+ if ($page > $totalPages) $page = $totalPages;
+ $offset = ($page - 1) * $perPage;
+
+ $idStmt = $pdo->prepare("
+ SELECT d.iddatadb FROM datadb d
+ WHERE {$whereSql}
+ ORDER BY d.excelrow ASC, d.iddatadb ASC
+ LIMIT {$perPage} OFFSET {$offset}
+ ");
+ $idStmt->execute($params);
+ $pageIds = array_map('intval', $idStmt->fetchAll(PDO::FETCH_COLUMN));
+
+ $config = buildGridConfig($pdo, $templateId);
+ $rows = buildGridRows($pdo, $pageIds, $config);
+
+ echo json_encode([
+ 'success' => true,
+ 'total' => $total,
+ 'page' => $page,
+ 'per_page' => $perPage,
+ 'total_pages' => $totalPages,
+ 'rows' => $rows,
+ 'mode' => 'selection',
+ ]);
+ } catch (Exception $e) {
+ error_log('filter_records (ids mode) error: ' . $e->getMessage());
+ echo json_encode(['success' => false, 'message' => $e->getMessage()]);
+ }
+ exit;
+}
+
$fixedAliasMap = [
'ClienteResponsabile' => 'cliente_responsabile_id',
'ClienteFornitore' => 'cliente_fornitore_id',
diff --git a/public/userarea/gridFilter.js b/public/userarea/gridFilter.js
index 1f9f056..7b8b721 100644
--- a/public/userarea/gridFilter.js
+++ b/public/userarea/gridFilter.js
@@ -39,6 +39,8 @@
let filterTotal = 0;
let originalData = null; // snapshot della pagina originale (per ripristino)
let filterReqSeq = 0;
+ let showingSelection = false; // true quando mostriamo l'UNIONE dei selezionati
+ let pagerFn = null; // paginazione corrente (applyServerFilter | showSelectedRecords)
function collectActiveFilters() {
const cols = meta().columns || [];
@@ -77,14 +79,16 @@
return;
}
el.style.display = "inline-flex";
+ const label = showingSelection ? "selezionati" : "trovati";
el.innerHTML =
`` +
- `${filterTotal} trovati · pag ${filterPage}/${filterTotalPages}` +
+ `${filterTotal} ${label} · pag ${filterPage}/${filterTotalPages}` +
``;
+ const go = pagerFn || applyServerFilter;
const prev = document.getElementById("filterPrevBtn");
const next = document.getElementById("filterNextBtn");
- if (prev) prev.addEventListener("click", () => applyServerFilter(filterPage - 1));
- if (next) next.addEventListener("click", () => applyServerFilter(filterPage + 1));
+ if (prev) prev.addEventListener("click", () => go(filterPage - 1));
+ if (next) next.addEventListener("click", () => go(filterPage + 1));
}
function restoreOriginal() {
@@ -128,6 +132,8 @@
return;
}
serverFiltered = true;
+ showingSelection = false;
+ pagerFn = applyServerFilter;
filterPage = json.page;
filterTotalPages = json.total_pages;
filterTotal = json.total;
@@ -140,6 +146,91 @@
}
}
+ // ── Mostra i SELEZIONATI (unione tra filtri diversi) ──────────────────
+ // La selezione si accumula tra filtri; questo carica dal server TUTTI i record
+ // selezionati (per id) e li mostra, paginati, a prescindere dai filtri correnti.
+ async function showSelectedRecords(page = 1) {
+ const ids = [...selected];
+ if (!ids.length) {
+ showingSelection = false;
+ updateToolbar();
+ return;
+ }
+ pagerFn = showSelectedRecords;
+ try {
+ const resp = await fetch("filter_records.php", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ template_id: parseInt(TEMPLATE_ID, 10),
+ all_users: SHOW_ALL,
+ importref: IMPORTREF,
+ status: "i",
+ ids: ids,
+ page: Math.max(1, page),
+ per_page: FILTER_PER_PAGE,
+ }),
+ });
+ const json = await resp.json();
+ if (!json.success) {
+ console.error("[gridFilter] mostra selezionati:", json.message);
+ return;
+ }
+ if (!originalData) originalData = [...data()];
+ showingSelection = true;
+ serverFiltered = true;
+ filterPage = json.page;
+ filterTotalPages = json.total_pages;
+ filterTotal = json.total;
+ swapData(json.rows || []);
+ updateFilterPager();
+ hidePagination(true);
+ updateToolbar();
+ } catch (e) {
+ console.error("[gridFilter] mostra selezionati fallita", e);
+ }
+ }
+
+ // Tumbler "Mostra selezionati" / "Torna al filtro".
+ function toggleShowSelected() {
+ if (!showingSelection) {
+ if (!selected.size) return;
+ showSelectedRecords(1);
+ } else {
+ exitSelectionView();
+ }
+ }
+
+ // Torna dal "mostra selezionati" al filtro corrente (o alla pagina originale).
+ function exitSelectionView() {
+ showingSelection = false;
+ pagerFn = applyServerFilter;
+ if (collectActiveFilters().length) {
+ applyServerFilter(1);
+ } else {
+ restoreOriginal();
+ }
+ updateToolbar();
+ }
+
+ // Deseleziona tutto.
+ function clearSelection() {
+ selected.clear();
+ document
+ .querySelectorAll("#gridRowContainer .grid-row.row-selected")
+ .forEach((el) => el.classList.remove("row-selected"));
+ document
+ .querySelectorAll(".filter-row-checkbox")
+ .forEach((cb) => (cb.checked = false));
+ const sa = document.getElementById("filterSelectAll");
+ if (sa) sa.checked = false;
+ if (showingSelection) {
+ exitSelectionView();
+ } else {
+ updateToolbar();
+ }
+ }
+
// "Seleziona tutti i filtrati": chiede al server TUTTI gli id del match e li seleziona.
async function selectAllMatching(on) {
if (!serverFiltered) return;
@@ -466,11 +557,15 @@
const cntEl = document.getElementById("filterSelCount");
if (cntEl) cntEl.textContent = count;
document.getElementById("filterDeleteBtn").disabled = count === 0;
- document.getElementById("filterRestrictBtn").disabled =
- count === 0 && !restricted;
- document.getElementById("filterRestrictBtn").innerHTML = restricted
- ? ' Mostra tutti'
- : ' Restringi selezione';
+
+ const showBtn = document.getElementById("filterRestrictBtn");
+ showBtn.disabled = count === 0 && !showingSelection;
+ showBtn.innerHTML = showingSelection
+ ? ' Torna al filtro'
+ : ' Mostra selezionati';
+
+ const clearSelBtn = document.getElementById("filterClearSelBtn");
+ if (clearSelBtn) clearSelBtn.disabled = count === 0;
}
// ── Main toggle ──
@@ -584,7 +679,8 @@
Selezionate: 0
-
+
+
`;
fBtn.parentNode.insertBefore(bar, fBtn.nextSibling);
@@ -598,7 +694,10 @@
.addEventListener("click", batchDelete);
document
.getElementById("filterRestrictBtn")
- .addEventListener("click", toggleRestrict);
+ .addEventListener("click", toggleShowSelected);
+ document
+ .getElementById("filterClearSelBtn")
+ .addEventListener("click", clearSelection);
}
// Svuota tutti i filtri di colonna (input + select) e torna alla pagina originale.