Fix: Umfassendes Refactoring des Print-CSS und Filter-Logik
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 37s

This commit is contained in:
Gemini CLI
2026-05-16 16:36:52 +00:00
parent e3381e9653
commit 34f7cf069d
2 changed files with 110 additions and 40 deletions

View File

@@ -85,7 +85,7 @@ $sql = "SELECT
u.username as creator_name, a.household_id, a.product_designation,
c.id AS category_id, c.name AS category_name, c.color AS category_color,
m.id AS manufacturer_id, m.name AS manufacturer_name,
a.storage_location_id, l2.name AS location_level2_name, l1.name AS location_level1_name
a.storage_location_id, l2.parent_id AS loc_parent_id, l2.name AS location_level2_name, l1.name AS location_level1_name
FROM articles a
JOIN users u ON a.user_id = u.id
LEFT JOIN categories c ON a.category_id = c.id
@@ -412,11 +412,32 @@ document.addEventListener('DOMContentLoaded', function () {
updateBulkUI();
});
document.querySelectorAll('.sortable-header').forEach(header => {
header.addEventListener('click', function() {
const sort = this.getAttribute('data-sort');
if (currentSortColumn === sort) {
currentSortDirection = currentSortDirection === 'asc' ? 'desc' : 'asc';
} else {
currentSortColumn = sort;
currentSortDirection = 'asc';
}
// Update icons
document.querySelectorAll('.sortable-header i.fa-sort, .sortable-header i.fa-sort-up, .sortable-header i.fa-sort-down').forEach(icon => {
icon.className = 'fas fa-sort text-muted ms-1';
});
const icon = this.querySelector('i');
icon.className = currentSortDirection === 'asc' ? 'fas fa-sort-up text-primary ms-1' : 'fas fa-sort-down text-primary ms-1';
renderTable();
});
});
function renderTable() {
const textValue = filterText.value.toLowerCase();
const categoryValue = filterCategory.value;
const manufacturerValue = filterManufacturer.value;
const isSearching = textValue.length > 0 || categoryValue || manufacturerValue;
const locationValue = filterLocation ? filterLocation.value : '';
const isSearching = textValue.length > 0 || categoryValue || manufacturerValue || locationValue;
function articleMatchesFilter(article) {
const matchesText = article.name.toLowerCase().includes(textValue) ||
@@ -424,7 +445,10 @@ document.addEventListener('DOMContentLoaded', function () {
(article.product_designation && article.product_designation.toLowerCase().includes(textValue));
const matchesCategory = !categoryValue || article.category_id == categoryValue;
const matchesManufacturer = !manufacturerValue || article.manufacturer_id == manufacturerValue;
return matchesText && matchesCategory && matchesManufacturer;
const locId = article.storage_location_id;
const locParentId = article.loc_parent_id;
const matchesLocation = !locationValue || locId == locationValue || locParentId == locationValue;
return matchesText && matchesCategory && matchesManufacturer && matchesLocation;
}
const filteredList = articlesHierarchical.filter(article => {
@@ -460,12 +484,23 @@ document.addEventListener('DOMContentLoaded', function () {
else cmp = a.localeCompare(b);
return currentSortDirection === 'asc' ? cmp : -cmp;
});
// Sort items inside groups by name
Object.keys(groupedArticles).forEach(key => {
groupedArticles[key].sort((a, b) => a.name.localeCompare(b.name));
});
} else {
groupedArticles['Suchergebnisse'] = [...filteredList];
// Flatten the list for sorting all items (including children) independent of hierarchy
const flatList = [];
function flatten(list) {
list.forEach(item => {
flatList.push(item);
if (item.children && item.children.length > 0) {
flatten(item.children);
}
});
}
flatten(filteredList);
groupedArticles['Suchergebnisse'] = flatList;
groupedArticles['Suchergebnisse'].sort((a, b) => {
let valA = a[currentSortColumn] || '';
let valB = b[currentSortColumn] || '';
@@ -515,9 +550,9 @@ document.addEventListener('DOMContentLoaded', function () {
if (!isCollapsed) {
items.forEach(article => {
tableHTML += generateRowHTML(article);
tableHTML += generateRowHTML(article, 0, isGrouped);
gridHTML += generateCardHTML(article);
if (article.children.length > 0) {
if (isGrouped && article.children.length > 0) {
article.children.forEach(child => {
gridHTML += generateCardHTML(child);
});
@@ -764,4 +799,6 @@ document.addEventListener('DOMContentLoaded', function () {
});
</script>
<?php require_once 'footer.php'; ?>/script>
<?php require_once 'footer.php'; ?>

View File

@@ -322,53 +322,86 @@ function showBarcode(token, name) {
new bootstrap.Modal(document.getElementById('barcodeModal')).show();
}
function showAllBarcodes(jsonStr, level1Name) {
const data = JSON.parse(jsonStr);
window.currentBarcodeData = [];
window.currentBarcodeLevel1Name = '';
window.showAllBarcodes = function(jsonStr, level1Name) {
window.currentBarcodeData = JSON.parse(jsonStr);
window.currentBarcodeLevel1Name = level1Name;
document.getElementById('printModalLabel').textContent = "QR-Codes für: " + level1Name;
window.renderAllBarcodes();
new bootstrap.Modal(document.getElementById('printModal')).show();
}
window.renderAllBarcodes = function() {
const container = document.getElementById('allBarcodesContainer');
container.innerHTML = '';
const baseUrl = window.location.origin + window.location.pathname.replace('storage_locations.php', 'public_location.php?token=');
document.getElementById('printModalLabel').textContent = "QR-Codes für: " + level1Name;
const sizeMM = document.getElementById('qrSizeInput') ? document.getElementById('qrSizeInput').value : 40;
data.forEach(item => {
window.currentBarcodeData.forEach(item => {
const url = baseUrl + item.token;
const col = document.createElement('div');
col.className = 'col-6 col-md-4 mb-4 text-center';
col.className = 'print-item text-center';
col.style.cssText = 'margin: 10px; page-break-inside: avoid; display: inline-block; width: ' + (parseInt(sizeMM) + 20) + 'mm;';
col.innerHTML = `
<div class="border p-3 bg-white" style="page-break-inside: avoid;">
<div class="bg-white">
<p class="fw-bold mb-2 text-truncate" style="font-size: 0.9rem;">${item.name}</p>
<img src="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(url)}" alt="QR Code" class="img-fluid mb-2">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${encodeURIComponent(url)}" alt="QR Code" style="border: 1px solid #000; padding: 1mm; width: ${sizeMM}mm; height: ${sizeMM}mm; box-sizing: border-box;" class="mb-2">
</div>
`;
container.appendChild(col);
});
new bootstrap.Modal(document.getElementById('printModal')).show();
}
function printDiv(divId) {
var printContents = document.getElementById(divId).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = `
<style>
body { font-family: sans-serif; background: none !important; background-color: white !important; }
.print-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; }
.print-item { text-align: center; margin-bottom: 20px; page-break-inside: avoid; }
p { margin: 0 0 5px 0; font-size: 14px; font-weight: bold; color: black !important; }
img { display: inline-block !important; }
</style>
<div class="print-grid">${printContents}</div>
`;
// Wait a brief moment to ensure QR code images from the external API are fully loaded before triggering print
setTimeout(function() {
window.print();
document.body.innerHTML = originalContents;
window.location.reload(); // Reload to restore event listeners after print
}, 500);
}
</script>
<style>
@media print {
body * {
visibility: hidden;
}
body {
background: none !important;
background-color: white !important;
}
#printModal, #printModal * {
visibility: visible;
}
#printModal {
position: absolute;
left: 0;
top: 0;
width: 100%;
margin: 0;
padding: 0;
}
.modal-header, .modal-footer, .d-print-none {
display: none !important;
}
#allBarcodesContainer {
display: flex !important;
flex-wrap: wrap !important;
justify-content: flex-start !important;
gap: 0 !important;
width: 100% !important;
}
.print-item {
display: inline-block !important;
}
.modal-dialog {
max-width: 100%;
margin: 0;
}
.modal-content {
border: none;
box-shadow: none;
}
.modal-backdrop {
display: none !important;
}
}
</style>
<div class="modal fade" id="printModal" tabindex="-1" aria-labelledby="printModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
@@ -385,7 +418,7 @@ function printDiv(divId) {
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
<button type="button" class="btn btn-primary" onclick="printDiv('allBarcodesContainer')"><i class="fas fa-print me-2"></i>Jetzt drucken</button>
<button type="button" class="btn btn-primary" onclick="window.print()"><i class="fas fa-print me-2"></i>Jetzt drucken</button>
</div>
</div>
</div>