feat(report): new unified compact report A4 portrait mode

This commit is contained in:
2026-08-27 11:41:44 +00:00
parent cc3c7889aa
commit 76ffa82e73
2 changed files with 151 additions and 0 deletions
+1
View File
@@ -157,6 +157,7 @@
<div class="export-buttons">
<button class="btn-primary" onclick="exportHTML()">📄 Exportar</button>
<button class="btn-primary" onclick="printReport()">🖨️ Imprimir</button>
<button class="btn-primary" onclick="printCompactReport()" style="background-color: #27ae60;">🖨️ Rel.Compacto</button>
</div>
</div>
</div>
+150
View File
@@ -1207,8 +1207,158 @@ window.calculateOptimization = calculateOptimization;
window.clearAll = clearAll;
window.exportHTML = exportHTML;
window.printReport = printReport;
window.printCompactReport = printCompactReport;
window.saveJob = saveJob;
function printCompactReport() {
const html = generateCompactReportHTML();
if (!html) {
showToast('Calcule a otimização primeiro', 'warning');
return;
}
const win = window.open('', '_blank');
win.document.write(html);
win.document.close();
setTimeout(() => {
win.print();
}, 500);
}
function generateCompactReportHTML() {
if (!lastResults) return null;
const { usedBars, totalWeight } = lastResults;
const dateStr = new Date().toLocaleDateString('pt-BR');
const timeStr = new Date().toLocaleTimeString('pt-BR');
const totalPieces = demandPieces.reduce((s, p) => s + p.qty, 0);
const jobTitle = document.getElementById('jobTitle').value.trim() || 'Relatório de Corte - Compacto';
const renderPieceGroups = (pieces) => {
const groups = {};
pieces.forEach(p => {
if (!groups[p.tag]) groups[p.tag] = 0;
groups[p.tag]++;
});
return Object.entries(groups).map(([tag, qt]) => `${tag} (${qt}x)`).join(', ');
};
let tableRows = usedBars.map((bar, idx) => {
const composition = renderPieceGroups(bar.pieces);
return `
<tr>
<td>${idx + 1}</td>
<td>${bar.barType}</td>
<td style="text-align: center;">${bar.count}</td>
<td style="text-align: right;">${bar.length} mm</td>
<td style="text-align: right; color: var(--danger);">${bar.remaining} mm</td>
<td>${composition}</td>
</tr>
`;
}).join('');
return `
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Relatório Compacto - ${dateStr}</title>
<style>
:root { --primary: #1a6b8f; --danger: #e74c3c; --gray: #bdc3c7; }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #555; font-family: 'Segoe UI', Arial, sans-serif; font-size: 10px; }
.page {
background: white;
width: 210mm;
min-height: 297mm;
margin: 20px auto;
padding: 10mm;
position: relative;
box-shadow: 0 0 10px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
}
@media print {
@page { size: A4 portrait; margin: 0; }
body { background: white; margin: 0; padding: 0; }
.page { margin: 0; box-shadow: none; border: none; min-height: 100vh; }
}
header {
border-bottom: 2px solid var(--primary);
padding-bottom: 10px;
margin-bottom: 10px;
color: var(--primary);
}
header h1 { font-size: 14pt; margin-bottom: 5px; }
header p { font-size: 8pt; color: #666; }
.content { flex: 1; }
.summary-box {
display: flex; justify-content: space-between;
background: #f4f4f4; padding: 8px; margin-bottom: 15px;
border: 1px solid #ddd; border-radius: 4px;
}
.summary-item { font-size: 9pt; }
.summary-item strong { display: block; font-size: 11pt; color: var(--primary); margin-top: 2px; }
table { width: 100%; border-collapse: collapse; font-size: 8pt; margin-bottom: 10px; }
th { background: var(--primary); color: white; text-align: left; padding: 6px; border: 1px solid #ddd; }
td { border: 1px solid #ddd; padding: 5px; }
tr:nth-child(even) { background: #f9f9f9; }
footer {
margin-top: 15px; border-top: 1px solid var(--gray);
padding-top: 10px; text-align: center; font-size: 8pt; color: #888;
}
</style>
</head>
<body>
<div class="page">
<header>
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h1>📊 ${jobTitle}</h1>
<p>Gerado em: ${dateStr} às ${timeStr}</p>
</div>
</div>
</header>
<div class="content">
<div class="summary-box">
<div class="summary-item">Total de Peças<strong>${totalPieces}</strong></div>
<div class="summary-item">Barras (Padrões)<strong>${usedBars.length}</strong></div>
<div class="summary-item">Peso Total (kg)<strong>${totalWeight.toFixed(2)}</strong></div>
<div class="summary-item">Aproveitamento Global<strong>${((1 - (lastResults.usedBars.reduce((s, b) => s + b.remaining, 0) / lastResults.usedBars.reduce((s, b) => s + b.length, 0))) * 100).toFixed(2)}%</strong></div>
</div>
<table>
<thead>
<tr>
<th style="width: 5%;">#</th>
<th style="width: 20%;">Perfil/Barra</th>
<th style="width: 8%; text-align: center;">Qtd</th>
<th style="width: 12%; text-align: right;">Comp. (mm)</th>
<th style="width: 12%; text-align: right;">Sobra (mm)</th>
<th style="width: 43%;">Composição (Tag x Qtd)</th>
</tr>
</thead>
<tbody>
${tableRows}
</tbody>
</table>
</div>
<footer>
Otimizador de Corte (Compacto) | ${totalPieces} Peças Processadas | Página 1 de 1
</footer>
</div>
</body>
</html>`;
}
window.loadJob = loadJob;
window.closeModal = closeModal;