Fechamento de Caixa - Tauri 2 initial commit
- Storage: SQLite local via rusqlite - Supabase: REST API via reqwest - Printer: USB ESC/POS for TM-T20 - Frontend: vanilla HTML (form-v9.3 ported) - Build: GitHub Actions for Linux/Windows/macOS
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
//! Comandos ESC/POS para impressoras térmicas 80mm
|
||||
//! Comandos Epson ESC/POS padrão — funciona com TM-T20 e compatíveis.
|
||||
|
||||
/// Inicializar impressora
|
||||
pub const INIT: &[u8] = b"\x1B\x40";
|
||||
/// Nova linha
|
||||
pub const LF: &[u8] = b"\x0A";
|
||||
/// Cortar papel (parcial)
|
||||
pub const CUT: &[u8] = b"\x1D\x56\x01";
|
||||
/// Cortar papel (total)
|
||||
pub const CUT_FULL: &[u8] = b"\x1D\x56\x00";
|
||||
/// Alimentar 3 linhas antes de cortar
|
||||
pub const FEED_CUT: &[u8] = b"\x1B\x64\x03";
|
||||
/// Negrito ON / OFF
|
||||
pub const BOLD_ON: &[u8] = b"\x1B\x45\x01";
|
||||
pub const BOLD_OFF: &[u8] = b"\x1B\x45\x00";
|
||||
/// Alinhamento
|
||||
pub const ALIGN_LEFT: &[u8] = b"\x1B\x61\x00";
|
||||
pub const ALIGN_CENTER: &[u8] = b"\x1B\x61\x01";
|
||||
pub const ALIGN_RIGHT: &[u8] = b"\x1B\x61\x02";
|
||||
/// Fonte normal / dupla
|
||||
pub const FONT_NORMAL: &[u8] = b"\x1B\x21\x00";
|
||||
pub const FONT_DOUBLE: &[u8] = b"\x1B\x21\x30";
|
||||
/// Linha divisória (48 colunas para 80mm)
|
||||
pub const DIVIDER: &str = "--------------------------------";
|
||||
|
||||
/// Monta texto centralizado com negrito + fonte dupla
|
||||
pub fn title(text: &str) -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(ALIGN_CENTER);
|
||||
out.extend_from_slice(BOLD_ON);
|
||||
out.extend_from_slice(FONT_DOUBLE);
|
||||
out.extend_from_slice(text.as_bytes());
|
||||
out.extend_from_slice(LF);
|
||||
out.extend_from_slice(FONT_NORMAL);
|
||||
out.extend_from_slice(BOLD_OFF);
|
||||
out
|
||||
}
|
||||
|
||||
/// Monta linha normal (alinhada à esquerda)
|
||||
pub fn line(text: &str) -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(ALIGN_LEFT);
|
||||
out.extend_from_slice(text.as_bytes());
|
||||
out.extend_from_slice(LF);
|
||||
out
|
||||
}
|
||||
|
||||
/// Monta linha centralizada
|
||||
pub fn line_center(text: &str) -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(ALIGN_CENTER);
|
||||
out.extend_from_slice(text.as_bytes());
|
||||
out.extend_from_slice(LF);
|
||||
out
|
||||
}
|
||||
|
||||
/// Monta linha em negrito
|
||||
pub fn line_bold(text: &str) -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(BOLD_ON);
|
||||
out.extend_from_slice(ALIGN_LEFT);
|
||||
out.extend_from_slice(text.as_bytes());
|
||||
out.extend_from_slice(LF);
|
||||
out.extend_from_slice(BOLD_OFF);
|
||||
out
|
||||
}
|
||||
|
||||
/// Monta linha com chave-valor alinhado (label 14 chars + espaço + valor 14 chars)
|
||||
pub fn kv(label: &str, value: &str) -> Vec<u8> {
|
||||
let padded_label = format!("{:<14}", label);
|
||||
let padded_value = format!("{:>14}", value);
|
||||
let line = format!("{} {}", padded_label, padded_value);
|
||||
let line = if line.len() > 48 { line[..48].to_string() } else { line };
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(ALIGN_LEFT);
|
||||
out.extend_from_slice(line.as_bytes());
|
||||
out.extend_from_slice(LF);
|
||||
out
|
||||
}
|
||||
|
||||
/// Monta linha divisória
|
||||
pub fn divider() -> Vec<u8> {
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(ALIGN_LEFT);
|
||||
out.extend_from_slice(DIVIDER.as_bytes());
|
||||
out.extend_from_slice(LF);
|
||||
out
|
||||
}
|
||||
|
||||
/// Monta espaço em branco (N linhas)
|
||||
pub fn blank_lines(n: u8) -> &'static [u8] {
|
||||
const BLANK: &[u8] = b"\n\n\n\n\n\n\n\n";
|
||||
&BLANK[..(n as usize).min(8)]
|
||||
}
|
||||
Reference in New Issue
Block a user