269 lines
7.6 KiB
JavaScript
269 lines
7.6 KiB
JavaScript
/*******************************************************************
|
|
|
|
Module : /assets/js/print.js
|
|
Desc. : JS Class Printer & Printer POS
|
|
Created By : Siau Pheng ([email protected]).
|
|
Created Date : May 27th, 2007.
|
|
Last Modified : November 2nd, 2026.
|
|
|
|
(c) 3FONIA Software; WWW.3FONIA.COM.
|
|
|
|
*******************************************************************
|
|
*
|
|
* Class Printer
|
|
*
|
|
* Standard Web Document Printing & Report Preview Class
|
|
*
|
|
* @license MIT, https://www.3fonia.com
|
|
* @copyright Copyright (c) 2008-2026, Siau Pheng <[email protected]>
|
|
*
|
|
* @param {object} options
|
|
* @param {string} options.url - Endpoint URL Print Page
|
|
* @param {number} [options.zoom=90] - Zoom percentage in viewer
|
|
* @param {Array} [options.params] - Request payload
|
|
*/
|
|
|
|
class Printer {
|
|
constructor(options = {}) {
|
|
this.url = typeof options === 'string' ? options : options.url || '';
|
|
this.zoom = options.zoom || 90;
|
|
this.params = options.params || [];
|
|
}
|
|
|
|
addParam(id, val) {
|
|
this.params.push(val !== undefined ? `${id}=${encodeURIComponent(val)}` : id);
|
|
return this;
|
|
}
|
|
|
|
doPrint() {
|
|
if (!this.url) {
|
|
console.warn('Url Laporan dibutuhkan!');
|
|
return;
|
|
}
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: this.url,
|
|
data: FoniaJS.RequestParam(this.params),
|
|
success: (txt) => {
|
|
let $printData = $('#dataPrint');
|
|
if (!$printData.length) {
|
|
$printData = $('<div/>', {
|
|
id: 'dataPrint',
|
|
class: 'd-none d-print-block print-body'
|
|
}).appendTo('body');
|
|
}
|
|
$printData.html(txt);
|
|
window.print();
|
|
},
|
|
error: typeof this.onFailure === 'function' ? this.onFailure : null
|
|
});
|
|
return this;
|
|
}
|
|
|
|
doPreview() {
|
|
if (!this.url) {
|
|
console.warn('Url Laporan dibutuhkan!');
|
|
return;
|
|
}
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: this.url,
|
|
data: FoniaJS.RequestParam(this.params),
|
|
success: (txt) => {
|
|
if (!txt) {
|
|
FoniaJS.showInfo('Tidak ada data untuk pembuatan laporan !');
|
|
return false;
|
|
}
|
|
const modalHtml = `
|
|
<div class="modal fade" id="winAPPPrint" tabindex="-1" role="dialog" data-bs-keyboard="false" data-bs-show="false" data-bs-backdrop="static" aria-labelledby="winAPPPrintLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-fs" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="winAPPPrintLabel">Preview Laporan</h5>
|
|
<div class="ms-auto">
|
|
<button class="btn me-2" id="tombCetak" type="button" aria-label="Cetak">
|
|
<i class="bi-printer me-2"></i><span aria-hidden="true">Cetak</span>
|
|
</button>
|
|
<button class="btn" type="button" data-bs-dismiss="modal" aria-label="Tutup">
|
|
<i class="bi-x-lg me-2"></i><span aria-hidden="true">Tutup</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="modal-body print-body" id="divPrintP">${txt}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
$('#winAPPPrint').modal('dispose').remove();
|
|
$(modalHtml)
|
|
.on('shown.bs.modal', () => {
|
|
$('#winAPPPrint #tombCetak').off('click').on('click', () => {
|
|
let $printData = $('#dataPrint');
|
|
if (!$printData.length) {
|
|
$printData = $('<div/>', {
|
|
id: 'dataPrint',
|
|
class: 'd-none d-print-block print-body'
|
|
}).appendTo('body');
|
|
}
|
|
$printData.html($('#divPrintP').html());
|
|
FoniaJS.closeWindow($('#winAPPPrint'));
|
|
window.print();
|
|
});
|
|
})
|
|
.on('hidden.bs.modal', function () {
|
|
$(this).remove();
|
|
})
|
|
.modal('show');
|
|
},
|
|
error: typeof this.onFailure === 'function' ? this.onFailure : null
|
|
});
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Class PrinterPos
|
|
*
|
|
* Direct Thermal POS Printer Class (via QZ Tray API)
|
|
*
|
|
* @license MIT, https://www.3fonia.com
|
|
* @copyright Copyright (c) 2008-2026, Siau Pheng <[email protected]>
|
|
*
|
|
* @param {object} options
|
|
* @param {string} options.url - Endpoint URL Print Page
|
|
* @param {number} [options.printer=FoniaJS._def_printer] - Printer Name
|
|
* @param {Array} [options.params] - Request payload
|
|
*/
|
|
|
|
class PrinterPos {
|
|
constructor(options = {}) {
|
|
this.url = typeof options === 'string' ? options : options.url || '';
|
|
this.printer = options.printer || (FoniaJS._def_printer ?? null);
|
|
this.cut_paper = options.cut_paper || '\x1D\x56\x41';
|
|
this.open_draw = options.open_draw || '\x1B\x70\x30\x19\x19';
|
|
this.chr_norm = options.chr_norm || '\x1B\x21\x01';
|
|
this.chr_bold = options.chr_bold || '\x1B\x21\x10';
|
|
this.chr_sbold = options.chr_sbold || '\x1B\x21\x31';
|
|
this.chr_uline = options.chr_uline || '\x1B\x21\x80';
|
|
this.params = options.params || [];
|
|
}
|
|
|
|
_detectPrinter() {
|
|
if (!qz?.websocket?.isActive?.()) {
|
|
FoniaJS.showInfo('Status Printer belum Active !');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
setPrinter(nprint) {
|
|
if (nprint != null) this.printer = nprint;
|
|
return this;
|
|
}
|
|
|
|
addParam(id, val) {
|
|
this.params.push(val !== undefined ? `${id}=${encodeURIComponent(val)}` : id);
|
|
return this;
|
|
}
|
|
|
|
async exec() {
|
|
if (!this._detectPrinter()) return;
|
|
|
|
let printerName = this.printer;
|
|
if (typeof printerName === 'object' && printerName !== null) {
|
|
if (printerName.name !== undefined) {
|
|
printerName = printerName.name;
|
|
} else if (printerName.file !== undefined) {
|
|
printerName = printerName.file;
|
|
} else if (printerName.host !== undefined) {
|
|
printerName = `${printerName.host}:${printerName.port}`;
|
|
}
|
|
}
|
|
printerName = printerName ?? 'None';
|
|
this.params.push(`Printer=${printerName}`);
|
|
this.doPrint(this.printer, this.url, this.params);
|
|
}
|
|
|
|
doPrint(printerName, url, params) {
|
|
const qzcfg = qz.configs.create(printerName);
|
|
new Request({
|
|
url,
|
|
sendParam: params,
|
|
onSuccess: (ajson) => {
|
|
if (typeof ajson === 'object' && ajson !== null) {
|
|
const printPayload = ajson.type === 'escp' ? this.genEscp(ajson) : this.genEpl(ajson);
|
|
qz.print(qzcfg, printPayload);
|
|
} else {
|
|
FoniaJS.showInfo('Error dalam proses Cetak.');
|
|
}
|
|
}
|
|
}).send();
|
|
}
|
|
|
|
genEscp(adata) {
|
|
const ohead = ['\x1B\x40', '\x1B\x61\x01'];
|
|
if (adata.config?.logo) {
|
|
ohead.push({
|
|
type: 'raw',
|
|
format: 'image',
|
|
flavor: 'base64',
|
|
data: adata.config.logo,
|
|
options: { language: 'ESCPOS', dotDensity: 'double' }
|
|
});
|
|
ohead.push('\x1B\x32');
|
|
}
|
|
if (parseInt(adata.config?.fontsize, 10) === 2) {
|
|
this.chr_norm = '\x1B\x21\x02';
|
|
}
|
|
if (Array.isArray(adata.header)) {
|
|
adata.header.forEach((headerLine, index) => {
|
|
if (index === 0 && !adata.config?.logo) ohead.push(this.chr_bold);
|
|
ohead.push(`${headerLine}\x0A`);
|
|
if (index === 0 && !adata.config?.logo) ohead.push(this.chr_norm);
|
|
});
|
|
}
|
|
|
|
let ocetak = [];
|
|
if (Array.isArray(adata.content)) {
|
|
adata.content.forEach((sheetContent) => {
|
|
if (!sheetContent?.length) return;
|
|
const osheet = [...ohead];
|
|
sheetContent.forEach((line) => {
|
|
const formattedLine = line
|
|
.replace('_SBOLD_', this.chr_sbold)
|
|
.replace('_BOLD_', this.chr_bold)
|
|
.replace('_NORM_', this.chr_norm)
|
|
.replace('_ULINE_', this.chr_uline);
|
|
osheet.push(`${formattedLine}\x0A`);
|
|
});
|
|
if (adata.config?.cutpaper) {
|
|
osheet.push(`${this.cut_paper}\x0A`);
|
|
}
|
|
ocetak = ocetak.concat(osheet);
|
|
});
|
|
}
|
|
|
|
let notaout = [];
|
|
if (adata.config?.opendraw) {
|
|
notaout.push(this.open_draw);
|
|
}
|
|
const times = adata.config?.times || 1;
|
|
for (let i = 0; i < times; i++) {
|
|
notaout = notaout.concat(ocetak);
|
|
}
|
|
return notaout;
|
|
}
|
|
|
|
genEpl(adata) {
|
|
const cetak = (adata.content || []).map((line) => `${line}\r\n`);
|
|
let notaout = [];
|
|
const times = adata.config?.times || 1;
|
|
|
|
for (let i = 0; i < times; i++) {
|
|
notaout = notaout.concat(cetak);
|
|
}
|
|
return notaout;
|
|
}
|
|
}
|