Barcode Scan + Barcode Print
This commit is contained in:
@@ -0,0 +1,641 @@
|
||||
<style>
|
||||
body {
|
||||
background: #f5f7fb;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
CARD
|
||||
=========================== */
|
||||
.main-card,
|
||||
.scanner-card,
|
||||
.table-card {
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
/*box-shadow: 0 8px 25px rgba(0, 0, 0, .08);*/
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
HEADER
|
||||
=========================== */
|
||||
.header-gradient {
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||||
color: #fff;
|
||||
padding: 22px 28px;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: rgba(255,255,255,.18);
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 8px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
SCANNER
|
||||
=========================== */
|
||||
.barcode-avatar {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
margin: auto;
|
||||
border-radius: 50%;
|
||||
background: #fff7e6;
|
||||
color: #f59e0b;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 45px;
|
||||
}
|
||||
|
||||
.barcode-code {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.form-control-lg {
|
||||
height: 60px;
|
||||
font-size: 22px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #f59e0b;
|
||||
box-shadow: 0 0 0 .2rem rgba(245, 158, 11, .2);
|
||||
}
|
||||
|
||||
.scan-note {
|
||||
color: #6c757d;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.camera-btn {
|
||||
height: 55px;
|
||||
border-radius: 12px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
TABLE
|
||||
=========================== */
|
||||
.table thead th {
|
||||
background: #d97706;
|
||||
color: #fff;
|
||||
border: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background: #fffaf0;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
BADGE
|
||||
=========================== */
|
||||
.badge-success-soft {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
border-radius: 30px;
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-danger-soft {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
border-radius: 30px;
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-warning-soft {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
border-radius: 30px;
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
font-weight: 600;
|
||||
}
|
||||
#reader{
|
||||
width:100%;
|
||||
min-height:280px;
|
||||
border-radius:12px;
|
||||
overflow:hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="card main-card">
|
||||
<!-- HEADER -->
|
||||
<div class="header-gradient">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h3 class="mb-1">
|
||||
<i class="fa fa-barcode"></i>
|
||||
Input Serial Number
|
||||
</h3>
|
||||
<div class="small">
|
||||
Silahkan scan Serial Number perangkat.
|
||||
Data akan otomatis tersimpan.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
<div class="info-box">
|
||||
<div class="small">
|
||||
Progress
|
||||
</div>
|
||||
<h5 class="font-weight-bold mb-2" id="progress_text">
|
||||
0 / 0 Barcode
|
||||
</h5>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-success" style="width:35%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BODY -->
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<!-- LEFT -->
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="card scanner-card">
|
||||
<div class="card-body">
|
||||
<div class="barcode-avatar">
|
||||
<i class="bi bi-qr-code-scan"></i>
|
||||
</div>
|
||||
<div class="text-center mt-3">
|
||||
<div class="barcode-code">
|
||||
ONU-250626-0007
|
||||
</div>
|
||||
<div class="scan-note mt-2">
|
||||
Barcode yang sedang menunggu Serial Number
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<center>
|
||||
<label class="font-weight-bold">
|
||||
Serial Number
|
||||
</label>
|
||||
<!-- <input
|
||||
type="text"
|
||||
id="serial_number"
|
||||
class="form-control form-control-lg text-center"
|
||||
placeholder="Scan Serial Number"
|
||||
autocomplete="off"
|
||||
autofocus
|
||||
>
|
||||
<small class="scan-note">
|
||||
Scanner akan otomatis menyimpan.
|
||||
</small>
|
||||
<button class="btn btn-warning btn-block camera-btn mt-4">
|
||||
<i class="fa fa-camera mr-2"></i>
|
||||
Scan dengan Kamera
|
||||
</button> -->
|
||||
<div id="scannerArea">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
id="serial_number"
|
||||
class="form-control form-control-lg text-center"
|
||||
placeholder="Scan Serial Number"
|
||||
autocomplete="off"
|
||||
autofocus>
|
||||
|
||||
<small class="scan-note">
|
||||
Scanner akan otomatis menyimpan.
|
||||
</small>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning btn-block camera-btn mt-4"
|
||||
id="btnCamera">
|
||||
|
||||
<i class="fa fa-camera mr-2"></i>
|
||||
Scan dengan Kamera
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="cameraArea" style="display:none;">
|
||||
|
||||
<div id="reader"></div>
|
||||
|
||||
<small class="scan-note d-block mt-2">
|
||||
Arahkan QR Code ke kamera.
|
||||
</small>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary btn-block mt-3"
|
||||
id="btnCloseCamera">
|
||||
|
||||
Tutup Kamera
|
||||
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</center>
|
||||
<div class="alert alert-warning mt-3 mb-0 text-center">
|
||||
<i class="fa fa-check-circle"></i>
|
||||
Auto Save Aktif
|
||||
</div>
|
||||
<input type="hidden" id="barcode_id">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- RIGHT -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card table-card">
|
||||
<div class="card-header bg-white">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
Daftar Barcode
|
||||
</h5>
|
||||
<span class="badge badge-warning px-3 py-2">
|
||||
20 Data
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
|
||||
<table class="table table-hover mb-0" id="tableBarcode">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60">No</th>
|
||||
<th>Barcode</th>
|
||||
<th>Serial Number</th>
|
||||
<th width="120">Status</th>
|
||||
<th width="80" class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<strong></strong>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<span class="badge-success-soft">
|
||||
<i class="fa fa-check mr-1"></i>
|
||||
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-sm btn-outline-danger">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
let ITEM_ID = `<?= $item_id; ?>` ;
|
||||
let isSaving = false;
|
||||
|
||||
$(document).ready(function () {
|
||||
loadData();
|
||||
$("#serial_number").focus();
|
||||
$("#serial_number").on("keypress", function (e) {
|
||||
if (e.which == 13) {
|
||||
e.preventDefault();
|
||||
if (!isSaving) {
|
||||
saveSerial();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function loadData() {
|
||||
$.getJSON( "<?= base_url(); ?>" + "items/load_data_barcode/" + ITEM_ID)
|
||||
.done(function (r) {
|
||||
render(r);
|
||||
})
|
||||
.fail(function () {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Oops...',
|
||||
text: 'Gagal mengambil data barcode.'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function saveSerial() {
|
||||
let serial = $("#serial_number").val().trim();
|
||||
if (serial == "") {
|
||||
$("#serial_number").focus();
|
||||
return;
|
||||
}
|
||||
isSaving = true;
|
||||
$("#serial_number")
|
||||
.prop("disabled", true);
|
||||
$.ajax({
|
||||
url: "<?= base_url(); ?>" + "items/save_serial_number",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {
|
||||
barcode_id: $("#barcode_id").val(),
|
||||
serial_number: serial
|
||||
},
|
||||
success: function (r) {
|
||||
isSaving = false;
|
||||
render(r);
|
||||
},
|
||||
error: function () {
|
||||
isSaving = false;
|
||||
$("#serial_number")
|
||||
.prop("disabled", false)
|
||||
.focus();
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Error",
|
||||
text: "Terjadi kesalahan pada server."
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function render(r) {
|
||||
|
||||
if (!r.status) {
|
||||
$("#serial_number")
|
||||
.val("")
|
||||
.prop("disabled", false)
|
||||
.focus();
|
||||
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Oops...",
|
||||
text: r.message
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Semua SN sudah selesai
|
||||
// =======================
|
||||
|
||||
if (r.next == null) {
|
||||
|
||||
$("#barcode_id").val("");
|
||||
$(".barcode-code").html("SELESAI");
|
||||
|
||||
$(".progress-bar").css("width", "100%");
|
||||
$("#progress_text").html(r.done + " / " + r.total);
|
||||
|
||||
if (r.item_status == "draft") {
|
||||
|
||||
$("#serial_number")
|
||||
.val("")
|
||||
.prop("disabled", false)
|
||||
.attr("placeholder", "Semua SN selesai. Edit melalui daftar di bawah jika ada yang salah.")
|
||||
.blur();
|
||||
|
||||
Swal.fire({
|
||||
icon: "success",
|
||||
title: "Selesai",
|
||||
text: "Semua Serial Number telah diinput. Karena status barang masih Draft, Anda masih dapat mengubah Serial Number melalui daftar di bawah."
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
$("#serial_number")
|
||||
.val("")
|
||||
.prop("disabled", true);
|
||||
|
||||
Swal.fire({
|
||||
icon: "success",
|
||||
title: "Selesai",
|
||||
text: "Semua Serial Number berhasil diinput."
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$("#barcode_id").val(r.next.id);
|
||||
$(".barcode-code").text(r.next.barcode);
|
||||
|
||||
$("#progress_text").text(r.done + " / " + r.total);
|
||||
|
||||
$(".progress-bar").css("width", r.percent + "%");
|
||||
|
||||
$("#serial_number")
|
||||
.val("")
|
||||
.prop("disabled", false)
|
||||
.attr("placeholder", "Scan Serial Number")
|
||||
.focus();
|
||||
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Table
|
||||
// =======================
|
||||
|
||||
let html = "";
|
||||
|
||||
$.each(r.list, function (i, v) {
|
||||
|
||||
html += "<tr>";
|
||||
html += "<td>" + (i + 1) + "</td>";
|
||||
html += "<td><strong>" + v.barcode + "</strong></td>";
|
||||
html += "<td>" + (v.serial_number ? v.serial_number : "-") + "</td>";
|
||||
|
||||
html += "<td>";
|
||||
|
||||
if (v.serial_number) {
|
||||
html += '<span class="badge-success-soft"><i class="fa fa-check mr-1"></i>Selesai</span>';
|
||||
} else {
|
||||
html += '<span class="badge-warning-soft">Menunggu</span>';
|
||||
}
|
||||
|
||||
html += "</td>";
|
||||
|
||||
html += '<td class="text-center">';
|
||||
|
||||
if (r.item_status == "draft") {
|
||||
|
||||
html += '<button class="btn btn-sm btn-outline-danger btnDelete" data-id="' + v.id + '">Delete</button>';
|
||||
|
||||
} else {
|
||||
|
||||
html += '<button class="btn btn-sm btn-outline-secondary" disabled>Locked</button>';
|
||||
|
||||
}
|
||||
|
||||
html += "</td>";
|
||||
html += "</tr>";
|
||||
|
||||
});
|
||||
|
||||
$("#tableBarcode tbody").html(html);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// function render(r) {
|
||||
// if (!r.status) {
|
||||
// $("#serial_number")
|
||||
// .val("")
|
||||
// .prop("disabled", false)
|
||||
// .focus();
|
||||
// Swal.fire({
|
||||
// icon: "error",
|
||||
// title: "Oops...",
|
||||
// text: r.message
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// if (r.next == null) {
|
||||
// $("#barcode_id").val("");
|
||||
// $(".barcode-code").html("SELESAI");
|
||||
// $("#serial_number")
|
||||
// .val("")
|
||||
// .prop("disabled", true);
|
||||
// $(".progress-bar")
|
||||
// .css("width", "100%");
|
||||
// $("#progress_text").html(r.done + " / " + r.total);
|
||||
// Swal.fire({
|
||||
// icon: "success",
|
||||
// title: "Selesai",
|
||||
// text: "Semua Serial Number berhasil diinput."
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// // Barcode Aktif
|
||||
// $("#barcode_id").val(r.next.id);
|
||||
// $(".barcode-code").text(r.next.barcode);
|
||||
// // Progress
|
||||
// $("#progress_text").text(r.done + " / " + r.total);
|
||||
// $(".progress-bar")
|
||||
// .css("width", r.percent + "%");
|
||||
// // Table
|
||||
// let html = "";
|
||||
// $.each(r.list, function (i, v) {
|
||||
// html += "<tr>";
|
||||
// html += "<td>" + (i + 1) + "</td>";
|
||||
// html += "<td><strong>" + v.barcode + "</strong></td>";
|
||||
// html += "<td>" + (v.serial_number ? v.serial_number : "-") + "</td>";
|
||||
// html += "<td>";
|
||||
// if (v.serial_number) {
|
||||
// html += '<span class="badge-success-soft"><i class="fa fa-check mr-1"></i>Selesai</span>';
|
||||
// } else {
|
||||
// html += '<span class="badge-warning-soft">Menunggu</span>';
|
||||
// }
|
||||
// html += "</td>";
|
||||
// html += '<td class="text-center">';
|
||||
// html += '<button class="btn btn-sm btn-outline-danger btnDelete" data-id="' + v.id + '">';
|
||||
// html += 'Delete';
|
||||
// html += '</button>';
|
||||
// html += '</td>';
|
||||
// html += "</tr>";
|
||||
// });
|
||||
// $("#tableBarcode tbody").html(html);
|
||||
// // Reset Input
|
||||
// $("#serial_number")
|
||||
// .val("")
|
||||
// .prop("disabled", false)
|
||||
// .focus();
|
||||
// }
|
||||
|
||||
$(document).on("click", ".btnDelete", function () {
|
||||
let id = $(this).data("id");
|
||||
Swal.fire({
|
||||
title: "Hapus Serial Number?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "Ya",
|
||||
cancelButtonText: "Batal"
|
||||
}).then(function (result) {
|
||||
if (!result.isConfirmed) return;
|
||||
$.post(
|
||||
"<?= base_url(); ?>" + "items/delete_serial_number",
|
||||
{
|
||||
barcode_id: id
|
||||
},
|
||||
function (r) {
|
||||
render(r);
|
||||
},
|
||||
"json"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
let html5QrCode=null;
|
||||
|
||||
$("#btnCamera").click(function(){
|
||||
|
||||
$("#scannerArea").hide();
|
||||
$("#cameraArea").show();
|
||||
|
||||
html5QrCode=new Html5Qrcode("reader");
|
||||
|
||||
html5QrCode.start(
|
||||
{
|
||||
facingMode:"environment"
|
||||
},
|
||||
{
|
||||
fps:10,
|
||||
qrbox:220
|
||||
},
|
||||
function(decodedText){
|
||||
|
||||
html5QrCode.stop().then(function(){
|
||||
|
||||
$("#cameraArea").hide();
|
||||
$("#scannerArea").show();
|
||||
|
||||
$("#serial_number")
|
||||
.val(decodedText);
|
||||
|
||||
saveSerial();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
$("#btnCloseCamera").click(function(){
|
||||
|
||||
if(html5QrCode){
|
||||
|
||||
html5QrCode.stop().then(function(){
|
||||
|
||||
$("#cameraArea").hide();
|
||||
$("#scannerArea").show();
|
||||
|
||||
$("#serial_number").focus();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
Reference in New Issue
Block a user