feat: alinha recibo ESC/POS com formato do screenshot
ReciboData agora recebe arrays (sangrias_arr, despesas_arr, etc.) to_escpos() gera: SANGRIAS → ENTRADAS → DESPESAS → PIX CNPJ → VALES → A RECEBER → CARTÕES → CANCELAMENTOS → TROCO → OBSERVAÇÕES → TOTAL SALDO CAIXA → SALDO ESPERADO → DIFERENÇA Preview impressao: modal com iframe 360x600px + botao Fechar + botao Imprimir — usuario consegue voltar ao app
This commit is contained in:
+64
-30
@@ -1329,44 +1329,78 @@ ${data.observacoes ? `<div class="obs">Obs: ${data.observacoes}</div>` : ''}
|
||||
}
|
||||
|
||||
function openPrintPreview(data) {
|
||||
// Cria iframe oculto para impressão — NÃO substitui o DOM do app
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.cssText = 'position:fixed;right:0;bottom:0;width:0;height:0;border:none;';
|
||||
iframe.id = 'print-iframe';
|
||||
document.body.appendChild(iframe);
|
||||
// Remove preview anterior se existir
|
||||
const existing = document.getElementById('print-preview-overlay');
|
||||
if (existing) document.body.removeChild(existing);
|
||||
|
||||
const html = buildPrintHTML(data);
|
||||
const printStyle = `
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'print-preview-overlay';
|
||||
overlay.style.cssText = `
|
||||
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: rgba(0,0,0,0.85); z-index: 99999;
|
||||
display: flex; flex-direction: column; align-items: center;
|
||||
font-family: 'Courier New', monospace;
|
||||
`;
|
||||
|
||||
const previewStyle = `
|
||||
<style>
|
||||
@media print {
|
||||
body { width: 80mm; margin: 0 auto; font-family: 'Courier New', monospace; font-size: 13px; }
|
||||
.no-print { display: none !important; }
|
||||
}
|
||||
body { padding: 10px; }
|
||||
.print-actions { text-align: center; margin-bottom: 10px; }
|
||||
.print-actions button { padding: 8px 16px; cursor: pointer; background: #e65100; color: #fff; border: none; border-radius: 4px; font-size: 14px; }
|
||||
body { width: 80mm; margin: 0 auto; font-family: 'Courier New', monospace; font-size: 13px; background: #fff; padding: 10px; }
|
||||
.header { text-align: center; margin-bottom: 8px; }
|
||||
.header h1 { font-size: 18px; }
|
||||
.header h2 { font-size: 14px; font-weight: normal; }
|
||||
hr { border: none; border-top: 1px dashed #000; margin: 6px 0; }
|
||||
.section-title { font-weight: bold; font-size: 14px; border-top: 1px dashed #000; padding-top: 4px; margin-top: 6px; }
|
||||
.row { display: flex; justify-content: space-between; padding: 2px 0; }
|
||||
table { width: 100%; border-collapse: collapse; font-size: 12px; }
|
||||
td { padding: 2px 4px; vertical-align: top; }
|
||||
td:nth-child(2) { text-align: right; }
|
||||
td:nth-child(3) { text-align: right; color: #555; font-size: 11px; }
|
||||
.grand-total { font-size: 16px; font-weight: bold; text-align: center; padding: 6px; border: 2px solid #000; margin: 8px 0; }
|
||||
.obs { font-size: 11px; color: #555; margin-top: 6px; white-space: pre-wrap; }
|
||||
.footer { text-align: center; font-size: 11px; color: #555; margin-top: 8px; }
|
||||
@media print { body { background: #fff; } }
|
||||
</style>
|
||||
`;
|
||||
|
||||
const html = buildPrintHTML(data);
|
||||
const fullHtml = `<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Recibo</title>${previewStyle}</head><body>${html}</body></html>`;
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.cssText = 'width:360px; height:600px; border:2px solid #555; margin-top:16px; background:#fff;';
|
||||
iframe.id = 'print-iframe';
|
||||
|
||||
const btnFechar = document.createElement('button');
|
||||
btnFechar.textContent = '✕ Fechar';
|
||||
btnFechar.style.cssText = `
|
||||
margin-top: 12px; padding: 10px 32px;
|
||||
background: #444; color: #fff; border: none; border-radius: 6px;
|
||||
font-size: 15px; cursor: pointer;
|
||||
`;
|
||||
btnFechar.onclick = () => {
|
||||
document.body.removeChild(overlay);
|
||||
};
|
||||
|
||||
const btnImprimir = document.createElement('button');
|
||||
btnImprimir.textContent = '🖨️ Imprimir';
|
||||
btnImprimir.style.cssText = `
|
||||
margin-top: 8px; padding: 10px 32px;
|
||||
background: #e65100; color: #fff; border: none; border-radius: 6px;
|
||||
font-size: 15px; cursor: pointer;
|
||||
`;
|
||||
btnImprimir.onclick = () => {
|
||||
iframe.contentWindow.focus();
|
||||
iframe.contentWindow.print();
|
||||
};
|
||||
|
||||
overlay.appendChild(iframe);
|
||||
overlay.appendChild(btnImprimir);
|
||||
overlay.appendChild(btnFechar);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
const iframeDoc = iframe.contentWindow.document;
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(`<!DOCTYPE html><html><head><title>Recibo</title>${printStyle}</head><body>${html}</body></html>`);
|
||||
iframeDoc.write(fullHtml);
|
||||
iframeDoc.close();
|
||||
|
||||
// Focus e imprime
|
||||
iframe.contentWindow.focus();
|
||||
iframe.contentWindow.print();
|
||||
|
||||
// Remove iframe após impressão
|
||||
iframe.contentWindow.onafterprint = () => {
|
||||
document.body.removeChild(iframe);
|
||||
};
|
||||
// Fallback: remove iframe após 5s (onafterprint pode não disparar em alguns browsers)
|
||||
setTimeout(() => {
|
||||
if (document.getElementById('print-iframe')) {
|
||||
document.body.removeChild(iframe);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function triggerWindowPrint() {
|
||||
|
||||
Reference in New Issue
Block a user