Dashboard: sezione Prodotti Aperti (conf parzialmente usate)
This commit is contained in:
@@ -753,6 +753,15 @@ function getStats(PDO $db): void {
|
||||
ORDER BY i.expiry_date ASC
|
||||
")->fetchAll();
|
||||
|
||||
// Opened (partially used conf items)
|
||||
$opened = $db->query("
|
||||
SELECT i.*, p.name, p.brand, p.category, p.unit, p.default_quantity, p.package_unit, p.image_url
|
||||
FROM inventory i JOIN products p ON i.product_id = p.id
|
||||
WHERE p.unit = 'conf' AND p.default_quantity > 0 AND p.package_unit IS NOT NULL
|
||||
AND i.quantity > 0 AND CAST(i.quantity AS REAL) != CAST(CAST(i.quantity AS INTEGER) AS REAL)
|
||||
ORDER BY i.updated_at DESC
|
||||
")->fetchAll();
|
||||
|
||||
echo json_encode([
|
||||
'total_products' => (int)$totalProducts,
|
||||
'total_items' => (float)$totalItems,
|
||||
@@ -761,6 +770,7 @@ function getStats(PDO $db): void {
|
||||
'recent_out' => (int)$recentOut,
|
||||
'expiring_soon' => $expiring,
|
||||
'expired' => $expired,
|
||||
'opened' => $opened,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -2908,6 +2908,22 @@ body {
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
/* ===== OPENED PRODUCTS SECTION ===== */
|
||||
.alert-opened {
|
||||
background: #eff6ff;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.alert-opened h3 {
|
||||
color: #1e40af;
|
||||
}
|
||||
|
||||
.alert-item-badge.opened {
|
||||
background: #3b82f6;
|
||||
color: #fff;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.review-hint {
|
||||
font-size: 0.8rem;
|
||||
color: #92400e;
|
||||
|
||||
@@ -813,6 +813,44 @@ async function loadDashboard() {
|
||||
|
||||
// Review suspicious quantities
|
||||
loadReviewItems();
|
||||
|
||||
// Opened (partially used) products
|
||||
const openedSection = document.getElementById('alert-opened');
|
||||
const openedList = document.getElementById('opened-list');
|
||||
if (statsData.opened && statsData.opened.length > 0) {
|
||||
openedSection.style.display = 'block';
|
||||
openedList.innerHTML = statsData.opened.map(item => {
|
||||
const locInfo = LOCATIONS[item.location] || { icon: '📦', label: item.location };
|
||||
const qty = parseFloat(item.quantity);
|
||||
const pkgSize = parseFloat(item.default_quantity);
|
||||
const pkgUnit = item.package_unit;
|
||||
const wholeConf = Math.floor(qty + 0.001);
|
||||
const frac = Math.round((qty - wholeConf) * 1000) / 1000;
|
||||
const remainderAmt = frac * pkgSize;
|
||||
const remainderText = formatSubRemainder(remainderAmt, pkgUnit);
|
||||
let qtyText = '';
|
||||
if (wholeConf > 0) {
|
||||
const unitLabels = { 'ml': 'ml', 'l': 'L', 'g': 'g', 'kg': 'kg' };
|
||||
const pkgLabel = unitLabels[pkgUnit] || pkgUnit;
|
||||
qtyText = `${wholeConf} conf (da ${pkgSize}${pkgLabel}) + ${remainderText}`;
|
||||
} else {
|
||||
qtyText = remainderText;
|
||||
}
|
||||
return `
|
||||
<div class="alert-item alert-item-clickable" onclick="showAlertItemDetail(${item.id}, ${item.product_id})">
|
||||
<div class="alert-item-info">
|
||||
<span class="alert-item-name">${escapeHtml(item.name)}</span>
|
||||
${item.brand ? `<span class="alert-item-brand">${escapeHtml(item.brand)}</span>` : ''}
|
||||
</div>
|
||||
<div class="alert-item-badges">
|
||||
<span class="alert-item-qty">${locInfo.icon} ${locInfo.label}</span>
|
||||
<span class="alert-item-badge opened">${qtyText}</span>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
} else {
|
||||
openedSection.style.display = 'none';
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('Dashboard load error:', err);
|
||||
|
||||
Binary file not shown.
+8
-2
@@ -9,7 +9,7 @@
|
||||
<title>Dispensa Manager</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260313g">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260313k">
|
||||
<!-- QuaggaJS for barcode scanning -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
||||
</head>
|
||||
@@ -69,6 +69,12 @@
|
||||
<div id="expiring-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Opened (partially used) products -->
|
||||
<div class="alert-section alert-opened" id="alert-opened" style="display:none">
|
||||
<h3>📦 Prodotti Aperti</h3>
|
||||
<div id="opened-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Review suspicious quantities -->
|
||||
<div class="alert-section alert-review" id="alert-review" style="display:none">
|
||||
<h3>🔍 Da revisionare</h3>
|
||||
@@ -878,6 +884,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/app.js?v=20260313j"></script>
|
||||
<script src="assets/js/app.js?v=20260313k"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user