Update besar apk finance
This commit is contained in:
@@ -1,406 +1,16 @@
|
||||
<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>
|
||||
Riwayat Perpindahan Barang
|
||||
</h3>
|
||||
<div class="small">
|
||||
Silahkan scan / input QR id Barang
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
</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="scan-note mt-2">
|
||||
Scan QR ID
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<center>
|
||||
<div id="scannerArea">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
id="serial_number"
|
||||
class="form-control form-control-lg text-center"
|
||||
placeholder="Scan / Input QR ID"
|
||||
autocomplete="off"
|
||||
autofocus>
|
||||
|
||||
<small class="scan-note">
|
||||
Scanner akan otomatis memanggil riwayat.
|
||||
</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>
|
||||
<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">
|
||||
Riwayat Perpindahan Barang
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body border-bottom" id="itemInfo">
|
||||
Belum ada data
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
|
||||
<table class="table table-hover mb-0" id="tableBarcode">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="60">No</th>
|
||||
<th>Date</th>
|
||||
<th>Type</th>
|
||||
<th>From</th>
|
||||
<th>To</th>
|
||||
<th>NOtes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php $inventory_title='Riwayat Barcode & Serial';$inventory_subtitle='Scan atau cari barcode untuk melihat identitas, posisi, saldo, reservasi, dan seluruh perpindahannya.';$this->load->view('inventory_professional/_module_nav',get_defined_vars());?>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-4"><section class="inventory-card h-100"><div class="inventory-card-head"><div><h5>Pencarian Unit</h5><p>Gunakan barcode, QR, atau serial number.</p></div></div><div class="p-3"><label class="form-label">Barcode / Serial Number</label><div class="input-group"><input id="scanCode" class="form-control form-control-lg" autocomplete="off" placeholder="Scan atau ketik kode"><button class="btn btn-primary" id="findBarcode"><i class="bi bi-search"></i></button></div><button class="btn btn-outline-primary w-100 mt-3" id="openCamera"><i class="bi bi-camera"></i> Buka Kamera Scanner</button><small class="text-muted d-block mt-3">Scanner hanya membaca data. Mutasi barang tetap dilakukan melalui dokumen sumber yang sesuai.</small></div></section></div>
|
||||
<div class="col-lg-8"><section class="inventory-card h-100"><div class="inventory-card-head"><div><h5>Identitas dan Posisi Barang</h5><p id="scanHint">Belum ada barcode yang dipilih.</p></div></div><div class="p-3" id="scanResult"><div class="inventory-empty"><i class="bi bi-upc-scan"></i><strong>Siap memindai</strong><small>Hasil akan tampil di sini tanpa membuka halaman baru.</small></div></div></section></div>
|
||||
</div>
|
||||
|
||||
<section class="inventory-card mt-3"><div class="inventory-card-head"><div><h5>Riwayat Perpindahan</h5><p>Urutan terbaru dari barcode atau serial yang dipilih.</p></div></div><div class="table-responsive"><table class="table inventory-table align-middle mb-0"><thead><tr><th>Waktu</th><th>Jenis</th><th>Dari</th><th>Ke</th><th class="text-end">Qty</th><th>Dokumen Sumber</th><th>Keterangan</th></tr></thead><tbody id="movementRows"><tr><td colspan="7" class="text-center text-muted py-5">Scan barcode untuk melihat riwayat.</td></tr></tbody></table></div></section>
|
||||
<div class="modal fade inventory-modal" id="cameraModal" tabindex="-1"><div class="modal-dialog modal-dialog-centered modal-lg"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Scanner Barcode / QR</h5><button class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div id="cameraReader"></div></div></div></div></div>
|
||||
<script>
|
||||
|
||||
$("#serial_number").keypress(function(e){
|
||||
if(e.which==13){
|
||||
searchHistory();
|
||||
}
|
||||
$(function(){
|
||||
const esc=v=>$('<div>').text(v==null||v===''?'-':v).html(),qty=v=>Number(v||0).toLocaleString('id-ID',{maximumFractionDigits:4});let scanner=null;
|
||||
function location(type,id){if(!type)return'-';return esc(String(type).replaceAll('_',' '))+(id?' #'+esc(id):'')}
|
||||
function find(){let code=$('#scanCode').val().trim();if(!code)return AppAlert.toast('Barcode atau serial wajib diisi.','warning');let b=$('#findBarcode').prop('disabled',true);$('#scanResult').html('<div class="inventory-loading"><span class="spinner-border spinner-border-sm"></span> Memuat identitas barang...</div>');$.get('<?=base_url('inventoryprofessional/scan')?>',{code:code}).done(function(r){let x=r.item,available=Math.max(0,Number(x.qty_sisa)-Number(x.reserved_qty)-Number(x.return_reserved_qty));$('#scanHint').text(x.kode_detail+' - '+x.nama_barang);$('#scanResult').html('<div class="scan-product"><span class="status-chip status-'+esc(x.status)+'">'+esc(String(x.status).replaceAll('_',' '))+'</span><h5>'+esc(x.kode_detail+' - '+x.nama_barang)+'</h5><div class="scan-grid"><span>Barcode<strong>'+esc(x.barcode)+'</strong></span><span>Serial Number<strong>'+esc(x.serial_number)+'</strong></span><span>Gudang<strong>'+esc(x.warehouse_name)+'</strong></span><span>Rak / Bin<strong>'+esc(x.bin_code)+'</strong></span><span>Batch<strong>'+esc(x.batch_no)+'</strong></span><span>Satuan<strong>'+esc(x.unit)+'</strong></span><span>Qty Fisik<strong>'+qty(x.qty_sisa)+'</strong></span><span>Reservasi / Retur<strong>'+qty(Number(x.reserved_qty)+Number(x.return_reserved_qty))+'</strong></span><span>Qty Tersedia<strong>'+qty(available)+'</strong></span></div></div>');$('#movementRows').html((x.history||[]).map(m=>'<tr><td>'+esc(m.created_at)+'</td><td><span class="status-chip">'+esc(String(m.movement_type||'-').replaceAll('_',' '))+'</span></td><td>'+location(m.from_type,m.from_id)+'</td><td>'+location(m.to_type,m.to_id)+'</td><td class="text-end">'+qty(m.qty)+'</td><td>'+esc(m.reference_type)+(m.reference_id?' #'+esc(m.reference_id):'')+'</td><td>'+esc(m.notes)+'</td></tr>').join('')||'<tr><td colspan="7" class="text-center text-muted py-4">Belum ada riwayat perpindahan.</td></tr>')}).fail(x=>{let m=x.responseJSON&&x.responseJSON.message||'Barcode tidak ditemukan.';$('#scanResult').html('<div class="inventory-empty"><i class="bi bi-exclamation-circle"></i><strong>'+esc(m)+'</strong></div>');$('#movementRows').html('<tr><td colspan="7" class="text-center text-muted py-4">Tidak ada data.</td></tr>');AppAlert.toast(m,'error')}).always(()=>b.prop('disabled',false))}
|
||||
$('#findBarcode').on('click',find);$('#scanCode').on('keydown',e=>{if(e.key==='Enter'){e.preventDefault();find()}});
|
||||
$('#openCamera').on('click',function(){let modal=bootstrap.Modal.getOrCreateInstance(document.getElementById('cameraModal'));modal.show();setTimeout(()=>{if(typeof Html5QrcodeScanner==='undefined')return AppAlert.toast('Library scanner belum tersedia. Gunakan input manual.','warning');scanner=new Html5QrcodeScanner('cameraReader',{fps:10,qrbox:{width:240,height:160}},false);scanner.render(code=>{$('#scanCode').val(code);scanner.clear().catch(()=>{});modal.hide();find()},()=>{})},250)});$('#cameraModal').on('hidden.bs.modal',function(){if(scanner)scanner.clear().catch(()=>{});scanner=null;$('#cameraReader').empty()});
|
||||
});
|
||||
function searchHistory(){
|
||||
let barcode=$("#serial_number").val().trim();
|
||||
if(barcode=="") return;
|
||||
$.ajax({
|
||||
url: `<?= base_url("items/scan_history"); ?>`,
|
||||
type:"POST",
|
||||
dataType:"json",
|
||||
data:{
|
||||
barcode:barcode
|
||||
},
|
||||
beforeSend:function(){
|
||||
$("#serial_number").prop("disabled",true);
|
||||
},
|
||||
success:function(r){
|
||||
$("#serial_number")
|
||||
.prop("disabled",false)
|
||||
.val("")
|
||||
.focus();
|
||||
if(!r.status){
|
||||
Swal.fire({
|
||||
icon:"error",
|
||||
text:r.message
|
||||
});
|
||||
return;
|
||||
}
|
||||
renderItem(r.item);
|
||||
renderHistory(r.history);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderItem(item){
|
||||
let html='';
|
||||
|
||||
html+='<div class="row">';
|
||||
|
||||
html+=' <div class="col-md-6">';
|
||||
|
||||
html+=' <h4 class="mb-3"><b>'+item.nama_barang+'</b></h4>';
|
||||
|
||||
html+=' <div class="row mb-2">';
|
||||
html+=' <div class="col-4 font-weight-bold">Kode</div>';
|
||||
html+=' <div class="col-1">:</div>';
|
||||
html+=' <div class="col-7">'+item.kode_detail+'</div>';
|
||||
html+=' </div>';
|
||||
|
||||
html+=' <div class="row mb-2">';
|
||||
html+=' <div class="col-4 font-weight-bold">Barcode</div>';
|
||||
html+=' <div class="col-1">:</div>';
|
||||
html+=' <div class="col-7">'+item.barcode+'</div>';
|
||||
html+=' </div>';
|
||||
|
||||
html+=' </div>';
|
||||
|
||||
html+=' <div class="col-md-6">';
|
||||
|
||||
html+=' <div class="row mb-2">';
|
||||
html+=' <div class="col-4 font-weight-bold">Serial Number</div>';
|
||||
html+=' <div class="col-1">:</div>';
|
||||
html+=' <div class="col-7">'+(item.serial_number ? item.serial_number : '-')+'</div>';
|
||||
html+=' </div>';
|
||||
|
||||
html+=' <div class="row mb-2">';
|
||||
html+=' <div class="col-4 font-weight-bold">Status</div>';
|
||||
html+=' <div class="col-1">:</div>';
|
||||
html+=' <div class="col-7">'+item.status+'</div>';
|
||||
html+=' </div>';
|
||||
|
||||
html+=' <div class="row mb-2">';
|
||||
html+=' <div class="col-4 font-weight-bold">Qty</div>';
|
||||
html+=' <div class="col-1">:</div>';
|
||||
html+=' <div class="col-7">'+item.qty_sisa+' / '+item.qty_awal+'</div>';
|
||||
html+=' </div>';
|
||||
|
||||
html+=' </div>';
|
||||
|
||||
html+='</div>';
|
||||
|
||||
$("#itemInfo").html(html);
|
||||
}
|
||||
|
||||
function renderHistory(list){
|
||||
let html='';
|
||||
$.each(list,function(i,v){
|
||||
html+="<tr>";
|
||||
html+="<td>"+(i+1)+"</td>";
|
||||
html+="<td>"+v.created_at+"</td>";
|
||||
html+="<td>"+v.movement_type+"</td>";
|
||||
html+="<td>"+(v.from_warehouse??v.from_type)+"</td>";
|
||||
html+="<td>"+(v.to_warehouse??v.to_type)+"</td>";
|
||||
html+="<td>"+v.notes+"</td>";
|
||||
html+="</tr>";
|
||||
});
|
||||
$("#tableBarcode tbody").html(html);
|
||||
}
|
||||
|
||||
|
||||
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