union ids
This commit is contained in:
@@ -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',
|
||||
|
||||
+109
-10
@@ -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 =
|
||||
`<button type="button" class="btn btn-outline-secondary btn-sm" id="filterPrevBtn" ${filterPage <= 1 ? "disabled" : ""}>‹</button>` +
|
||||
`<span style="font-size:12px;color:#333;">${filterTotal} trovati · pag ${filterPage}/${filterTotalPages}</span>` +
|
||||
`<span style="font-size:12px;color:#333;">${filterTotal} ${label} · pag ${filterPage}/${filterTotalPages}</span>` +
|
||||
`<button type="button" class="btn btn-outline-secondary btn-sm" id="filterNextBtn" ${filterPage >= filterTotalPages ? "disabled" : ""}>›</button>`;
|
||||
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
|
||||
? '<i class="fas fa-eye"></i> Mostra tutti'
|
||||
: '<i class="fas fa-compress"></i> Restringi selezione';
|
||||
|
||||
const showBtn = document.getElementById("filterRestrictBtn");
|
||||
showBtn.disabled = count === 0 && !showingSelection;
|
||||
showBtn.innerHTML = showingSelection
|
||||
? '<i class="fas fa-eye"></i> Torna al filtro'
|
||||
: '<i class="fas fa-list-check"></i> Mostra selezionati';
|
||||
|
||||
const clearSelBtn = document.getElementById("filterClearSelBtn");
|
||||
if (clearSelBtn) clearSelBtn.disabled = count === 0;
|
||||
}
|
||||
|
||||
// ── Main toggle ──
|
||||
@@ -584,7 +679,8 @@
|
||||
<span id="filterPager" style="display:none;align-items:center;gap:6px;"></span>
|
||||
<button type="button" id="filterClearBtn" class="btn btn-outline-secondary btn-sm"><i class="fas fa-times"></i> Pulisci filtri</button>
|
||||
<span style="font-size:12px;color:#555;">Selezionate: <strong id="filterSelCount">0</strong></span>
|
||||
<button type="button" id="filterRestrictBtn" class="btn btn-outline-primary btn-sm"><i class="fas fa-compress"></i> Restringi selezione</button>
|
||||
<button type="button" id="filterRestrictBtn" class="btn btn-outline-primary btn-sm"><i class="fas fa-list-check"></i> Mostra selezionati</button>
|
||||
<button type="button" id="filterClearSelBtn" class="btn btn-outline-secondary btn-sm"><i class="fas fa-square"></i> Deseleziona</button>
|
||||
<button type="button" id="filterDeleteBtn" class="btn btn-outline-danger btn-sm"><i class="fas fa-trash"></i> Elimina selezionati</button>
|
||||
`;
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user