feat(ui): order totals, decimals, mobile modal cards, set editing
- Dashboard/Logs: Total column with 2 decimals (order_total) - Order detail modal: totals summary row (items total + order total) - Order detail modal mobile: compact article cards (d-md-none) - Mappings: openEditModal loads all CODMATs for SKU, saveMapping replaces entire set via delete-all + batch POST - Add project-specific team agents: ui-templates, ui-js, ui-verify, backend-api - CLAUDE.md: mandatory preview approval before implementation, fix-loop after verification, server must start via start.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -151,10 +151,11 @@ async function loadRunOrders(runId, statusFilter, page) {
|
||||
const orders = data.orders || [];
|
||||
|
||||
if (orders.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-muted py-3">Nicio comanda</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-3">Nicio comanda</td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = orders.map((o, i) => {
|
||||
const dateStr = fmtDate(o.order_date);
|
||||
const orderTotal = o.order_total != null ? Number(o.order_total).toFixed(2) : '-';
|
||||
return `<tr style="cursor:pointer" onclick="openOrderDetail('${esc(o.order_number)}')">
|
||||
<td>${(ordersPage - 1) * 50 + i + 1}</td>
|
||||
<td>${dateStr}</td>
|
||||
@@ -162,6 +163,7 @@ async function loadRunOrders(runId, statusFilter, page) {
|
||||
<td>${esc(o.customer_name)}</td>
|
||||
<td>${o.items_count || 0}</td>
|
||||
<td class="text-nowrap">${statusDot(o.status)} ${logStatusText(o.status)}</td>
|
||||
<td>${orderTotal}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
@@ -179,7 +181,7 @@ async function loadRunOrders(runId, statusFilter, page) {
|
||||
dateFmt = d.slice(8, 10) + '.' + d.slice(5, 7) + '.' + d.slice(2, 4);
|
||||
if (d.length >= 16) dateFmt += ' ' + d.slice(11, 16);
|
||||
}
|
||||
const totalStr = o.order_total ? Math.round(o.order_total) : '';
|
||||
const totalStr = o.order_total ? Number(o.order_total).toFixed(2) : '';
|
||||
return `<div class="flat-row" onclick="openOrderDetail('${esc(o.order_number)}')" style="font-size:0.875rem">
|
||||
${statusDot(o.status)}
|
||||
<span style="color:#6b7280" class="text-nowrap">${dateFmt}</span>
|
||||
@@ -318,6 +320,12 @@ async function openOrderDetail(orderNumber) {
|
||||
document.getElementById('detailIdAdresaLivr').textContent = '-';
|
||||
document.getElementById('detailItemsBody').innerHTML = '<tr><td colspan="8" class="text-center">Se incarca...</td></tr>';
|
||||
document.getElementById('detailError').style.display = 'none';
|
||||
const detailItemsTotal = document.getElementById('detailItemsTotal');
|
||||
if (detailItemsTotal) detailItemsTotal.textContent = '-';
|
||||
const detailOrderTotal = document.getElementById('detailOrderTotal');
|
||||
if (detailOrderTotal) detailOrderTotal.textContent = '-';
|
||||
const mobileContainer = document.getElementById('detailItemsMobile');
|
||||
if (mobileContainer) mobileContainer.innerHTML = '';
|
||||
|
||||
const modalEl = document.getElementById('orderDetailModal');
|
||||
const existing = bootstrap.Modal.getInstance(modalEl);
|
||||
@@ -353,6 +361,36 @@ async function openOrderDetail(orderNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update totals row
|
||||
const itemsTotal = items.reduce((sum, item) => sum + (Number(item.price || 0) * Number(item.quantity || 0)), 0);
|
||||
document.getElementById('detailItemsTotal').textContent = itemsTotal.toFixed(2) + ' lei';
|
||||
document.getElementById('detailOrderTotal').textContent = order.order_total != null ? Number(order.order_total).toFixed(2) + ' lei' : '-';
|
||||
|
||||
// Mobile article cards
|
||||
const mobileContainer = document.getElementById('detailItemsMobile');
|
||||
if (mobileContainer) {
|
||||
mobileContainer.innerHTML = items.map(item => {
|
||||
let statusLabel = '';
|
||||
switch (item.mapping_status) {
|
||||
case 'mapped': statusLabel = '<span class="badge bg-success">Mapat</span>'; break;
|
||||
case 'direct': statusLabel = '<span class="badge bg-info">Direct</span>'; break;
|
||||
case 'missing': statusLabel = '<span class="badge bg-warning">Lipsa</span>'; break;
|
||||
default: statusLabel = '<span class="badge bg-secondary">?</span>';
|
||||
}
|
||||
const codmat = item.codmat || '-';
|
||||
return `<div class="detail-item-card">
|
||||
<div class="card-sku">${esc(item.sku)}</div>
|
||||
<div class="card-name">${esc(item.product_name || '-')}</div>
|
||||
<div class="card-details">
|
||||
<span>x${item.quantity || 0}</span>
|
||||
<span>${item.price != null ? Number(item.price).toFixed(2) : '-'} lei</span>
|
||||
<span><code>${esc(codmat)}</code></span>
|
||||
<span>${statusLabel}</span>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
document.getElementById('detailItemsBody').innerHTML = items.map(item => {
|
||||
let statusBadge;
|
||||
switch (item.mapping_status) {
|
||||
|
||||
Reference in New Issue
Block a user