barcode enhancing
This commit is contained in:
parent
07acd2fa84
commit
8fccefd923
11
index.php
11
index.php
@ -12194,25 +12194,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body text-center">
|
<div class="modal-body text-center">
|
||||||
<div id="barcodeContainer" class="p-4 bg-white border mb-3 mx-auto" style="width: fit-content;">
|
<div id="barcodeContainer" class="p-4 bg-white border mb-3 mx-auto" style="width: fit-content; max-width: 100%;">
|
||||||
<div id="barcodeLabelName" class="fw-bold small mb-1"></div>
|
<div id="barcodeLabelName" class="fw-bold small mb-1"></div>
|
||||||
<svg id="barcodeSvg"></svg>
|
<svg id="barcodeSvg" style="max-width: 100%; height: auto;"></svg>
|
||||||
<div id="barcodeLabelPrice" class="fw-bold mt-1"></div>
|
<div id="barcodeLabelPrice" class="fw-bold mt-1"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label small">Number of Labels</label>
|
<label class="form-label small">Number of Labels</label>
|
||||||
<input type="number" id="barcodeQty" class="form-control form-control-sm mx-auto" value="1" min="1" style="width: 80px;">
|
<input type="number" id="barcodeQty" class="form-control form-control-sm mx-auto" value="1" min="1" style="width: 80px;">
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3 mx-auto" style="max-width: 200px;">
|
<div class="row mb-2 mx-auto" style="max-width: 200px;">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<label class="form-label small">Width (mm)</label>
|
<label class="form-label small">Width (mm)</label>
|
||||||
<input type="number" id="barcodeWidth" class="form-control form-control-sm" value="40" min="10">
|
<input type="number" id="barcodeWidth" class="form-control form-control-sm" value="50" min="10">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<label class="form-label small">Height (mm)</label>
|
<label class="form-label small">Height (mm)</label>
|
||||||
<input type="number" id="barcodeHeight" class="form-control form-control-sm" value="25" min="10">
|
<input type="number" id="barcodeHeight" class="form-control form-control-sm" value="30" min="10">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-text text-center mb-1">For best scanner reliability, start at 50 × 30 mm or larger.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Close" data-ar="إغلاق">Close</button>
|
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Close" data-ar="إغلاق">Close</button>
|
||||||
|
|||||||
@ -1,34 +1,170 @@
|
|||||||
|
function escapeBarcodeLabelHtml(value) {
|
||||||
|
return String(value || '')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSingleBarcodeLabelData() {
|
||||||
|
return window.currentSingleBarcodeLabel || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSingleBarcodePrintDimensions() {
|
||||||
|
return {
|
||||||
|
width: Math.max(parseInt(document.getElementById('barcodeWidth').value, 10) || 50, 10),
|
||||||
|
height: Math.max(parseInt(document.getElementById('barcodeHeight').value, 10) || 30, 10)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm) {
|
||||||
|
const skuText = String(sku || '');
|
||||||
|
const skuLength = skuText.length;
|
||||||
|
const compact = labelWidthMm <= 40 || labelHeightMm <= 25;
|
||||||
|
const extraCompact = labelWidthMm <= 32 || labelHeightMm <= 20;
|
||||||
|
const showValue = !extraCompact && labelHeightMm >= 24 && skuLength <= 18;
|
||||||
|
|
||||||
|
let moduleWidth = 1.8;
|
||||||
|
if (skuLength >= 18 || labelWidthMm <= 35) {
|
||||||
|
moduleWidth = 1.1;
|
||||||
|
} else if (skuLength >= 14 || labelWidthMm <= 40) {
|
||||||
|
moduleWidth = 1.3;
|
||||||
|
} else if (labelWidthMm <= 50) {
|
||||||
|
moduleWidth = 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
let barcodeHeight = 56;
|
||||||
|
if (labelHeightMm <= 20) {
|
||||||
|
barcodeHeight = 30;
|
||||||
|
} else if (labelHeightMm <= 25) {
|
||||||
|
barcodeHeight = 38;
|
||||||
|
} else if (labelHeightMm <= 30) {
|
||||||
|
barcodeHeight = 46;
|
||||||
|
} else if (labelHeightMm <= 35) {
|
||||||
|
barcodeHeight = 56;
|
||||||
|
} else {
|
||||||
|
barcodeHeight = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
const quietZone = extraCompact ? 4 : compact ? 6 : 10;
|
||||||
|
|
||||||
|
return {
|
||||||
|
format: "CODE128",
|
||||||
|
lineColor: "#000",
|
||||||
|
width: moduleWidth,
|
||||||
|
height: barcodeHeight,
|
||||||
|
displayValue: showValue,
|
||||||
|
fontSize: compact ? 10 : 12,
|
||||||
|
textMargin: compact ? 2 : 4,
|
||||||
|
margin: quietZone,
|
||||||
|
marginTop: 0,
|
||||||
|
marginBottom: showValue ? 2 : 0,
|
||||||
|
fontOptions: "bold"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSingleBarcodeNameHtml(nameAr, nameEn) {
|
||||||
|
const lines = [];
|
||||||
|
if (nameAr) {
|
||||||
|
lines.push('<div class="label-name-ar">' + escapeBarcodeLabelHtml(nameAr) + '</div>');
|
||||||
|
}
|
||||||
|
if (nameEn) {
|
||||||
|
lines.push('<div class="label-name-en">' + escapeBarcodeLabelHtml(nameEn) + '</div>');
|
||||||
|
}
|
||||||
|
return lines.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSingleBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) {
|
||||||
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||||
|
JsBarcode(svg, sku, getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm));
|
||||||
|
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||||
|
svg.style.width = '100%';
|
||||||
|
svg.style.height = 'auto';
|
||||||
|
return svg.outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSingleBarcodePreview() {
|
||||||
|
const label = getSingleBarcodeLabelData();
|
||||||
|
if (!label) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dimensions = getSingleBarcodePrintDimensions();
|
||||||
|
const width = dimensions.width;
|
||||||
|
const height = dimensions.height;
|
||||||
|
const nameContainer = document.getElementById('barcodeLabelName');
|
||||||
|
const priceContainer = document.getElementById('barcodeLabelPrice');
|
||||||
|
const previewContainer = document.getElementById('barcodeContainer');
|
||||||
|
const svg = document.getElementById('barcodeSvg');
|
||||||
|
|
||||||
|
if (!nameContainer || !priceContainer || !previewContainer || !svg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||||
|
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
||||||
|
previewContainer.style.width = Math.min(Math.max(width * 4, 180), 320) + 'px';
|
||||||
|
previewContainer.style.maxWidth = '100%';
|
||||||
|
previewContainer.style.padding = height <= 25 ? '12px' : '16px';
|
||||||
|
|
||||||
|
svg.innerHTML = '';
|
||||||
|
JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height));
|
||||||
|
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||||
|
svg.style.width = '100%';
|
||||||
|
svg.style.height = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSingleBarcodePreviewControls() {
|
||||||
|
['barcodeWidth', 'barcodeHeight'].forEach((id) => {
|
||||||
|
const input = document.getElementById(id);
|
||||||
|
if (!input || input.dataset.barcodePreviewBound === '1') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.dataset.barcodePreviewBound = '1';
|
||||||
|
input.addEventListener('input', renderSingleBarcodePreview);
|
||||||
|
input.addEventListener('change', renderSingleBarcodePreview);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initSingleBarcodePreviewControls();
|
||||||
|
|
||||||
window.printItemBarcode = function(sku, nameAr, nameEn, price) {
|
window.printItemBarcode = function(sku, nameAr, nameEn, price) {
|
||||||
if (!sku) {
|
if (!sku) {
|
||||||
Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error');
|
Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.getElementById('barcodeLabelName').innerHTML = '<div style="font-weight:bold; font-size:12px; direction:rtl; margin-bottom:2px;">' + nameAr + '</div><div style="font-size:10px;">' + nameEn + '</div>';
|
|
||||||
document.getElementById('barcodeLabelPrice').textContent = 'OMR ' + price;
|
|
||||||
|
|
||||||
JsBarcode("#barcodeSvg", sku, {
|
window.currentSingleBarcodeLabel = {
|
||||||
format: "CODE128",
|
sku: String(sku),
|
||||||
lineColor: "#000",
|
nameAr: nameAr || '',
|
||||||
width: 2,
|
nameEn: nameEn || '',
|
||||||
height: 50,
|
price: price || ''
|
||||||
displayValue: true
|
};
|
||||||
});
|
|
||||||
|
renderSingleBarcodePreview();
|
||||||
|
|
||||||
const modal = new bootstrap.Modal(document.getElementById('barcodePrintModal'));
|
const modal = new bootstrap.Modal(document.getElementById('barcodePrintModal'));
|
||||||
modal.show();
|
modal.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
window.executeBarcodePrint = function() {
|
window.executeBarcodePrint = function() {
|
||||||
const qty = parseInt(document.getElementById('barcodeQty').value) || 1;
|
const qty = Math.max(parseInt(document.getElementById('barcodeQty').value, 10) || 1, 1);
|
||||||
const width = parseInt(document.getElementById('barcodeWidth').value) || 40;
|
const dimensions = getSingleBarcodePrintDimensions();
|
||||||
const height = parseInt(document.getElementById('barcodeHeight').value) || 25;
|
const width = dimensions.width;
|
||||||
|
const height = dimensions.height;
|
||||||
|
const label = getSingleBarcodeLabelData();
|
||||||
|
|
||||||
// Get content
|
if (!label) {
|
||||||
const nameHtml = document.getElementById('barcodeLabelName').innerHTML;
|
return;
|
||||||
const price = document.getElementById('barcodeLabelPrice').innerText;
|
}
|
||||||
const svg = document.getElementById('barcodeSvg').outerHTML;
|
|
||||||
|
const nameHtml = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||||
|
const price = label.price ? 'OMR ' + escapeBarcodeLabelHtml(label.price) : '';
|
||||||
|
const svg = buildSingleBarcodeSvgMarkup(label.sku, width, height);
|
||||||
|
const compactClass = width <= 40 || height <= 25 ? 'label-compact' : '';
|
||||||
|
|
||||||
// Create a hidden iframe
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.style.position = 'absolute';
|
iframe.style.position = 'absolute';
|
||||||
iframe.style.width = '0px';
|
iframe.style.width = '0px';
|
||||||
@ -41,10 +177,10 @@
|
|||||||
let labelsHtml = '';
|
let labelsHtml = '';
|
||||||
for (let i = 0; i < qty; i++) {
|
for (let i = 0; i < qty; i++) {
|
||||||
labelsHtml += `
|
labelsHtml += `
|
||||||
<div class="label-container">
|
<div class="label-container ${compactClass}">
|
||||||
<div class="label-name" style="height: auto; overflow: visible;">${nameHtml}</div>
|
${nameHtml ? `<div class="label-name">${nameHtml}</div>` : ''}
|
||||||
${svg}
|
<div class="barcode-wrap">${svg}</div>
|
||||||
<div class="label-price">${price}</div>
|
${price ? `<div class="label-price">${price}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -62,17 +198,62 @@
|
|||||||
page-break-after: always;
|
page-break-after: always;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 1mm;
|
padding: 1.5mm 2mm;
|
||||||
|
gap: 0.75mm;
|
||||||
}
|
}
|
||||||
.label-container:last-child { page-break-after: avoid; }
|
.label-container:last-child { page-break-after: avoid; }
|
||||||
.label-name { font-weight: bold; margin-bottom: 2px; line-height: 1.1; max-width: 100%; }
|
.label-name {
|
||||||
.label-price { font-size: 12px; font-weight: bold; margin-top: 2px; }
|
width: 100%;
|
||||||
svg { max-width: 100%; height: auto; max-height: 70%; display: block; }
|
max-width: 100%;
|
||||||
|
line-height: 1.05;
|
||||||
|
}
|
||||||
|
.label-name-ar,
|
||||||
|
.label-name-en {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.label-name-ar {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 11px;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
.label-name-en { font-size: 9px; }
|
||||||
|
.label-price {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.label-compact {
|
||||||
|
padding: 1mm 1.5mm;
|
||||||
|
gap: 0.5mm;
|
||||||
|
}
|
||||||
|
.label-compact .label-name-ar { font-size: 10px; }
|
||||||
|
.label-compact .label-name-en { font-size: 8px; }
|
||||||
|
.label-compact .label-price { font-size: 10px; }
|
||||||
|
.barcode-wrap {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 1.5mm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.barcode-wrap svg {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user