feat(report): new unified compact report A4 portrait mode
This commit is contained in:
@@ -157,6 +157,7 @@
|
|||||||
<div class="export-buttons">
|
<div class="export-buttons">
|
||||||
<button class="btn-primary" onclick="exportHTML()">📄 Exportar</button>
|
<button class="btn-primary" onclick="exportHTML()">📄 Exportar</button>
|
||||||
<button class="btn-primary" onclick="printReport()">🖨️ Imprimir</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+150
@@ -1207,8 +1207,158 @@ window.calculateOptimization = calculateOptimization;
|
|||||||
window.clearAll = clearAll;
|
window.clearAll = clearAll;
|
||||||
window.exportHTML = exportHTML;
|
window.exportHTML = exportHTML;
|
||||||
window.printReport = printReport;
|
window.printReport = printReport;
|
||||||
|
window.printCompactReport = printCompactReport;
|
||||||
window.saveJob = saveJob;
|
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.loadJob = loadJob;
|
||||||
window.closeModal = closeModal;
|
window.closeModal = closeModal;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user