Files
accounting_dev/application/views/peralatan_teknisi/layout.php
T
2026-07-24 00:01:55 +07:00

1263 lines
48 KiB
PHP

<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.4.1/css/responsive.bootstrap5.min.css">
<style>
:root {
--tech-primary: #ff9800;
--tech-primary-light: #fff3e0;
--tech-primary-dark: #e65100;
}
body {
background: #f5f7fb;
}
.tech-card {
border: none;
border-radius: 14px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
background: #fff;
}
.tech-card .card-header-custom {
background: linear-gradient(135deg, var(--tech-primary), var(--tech-primary-dark));
color: #fff;
padding: 14px 20px;
font-weight: 600;
font-size: 15px;
}
.tech-card .card-body {
padding: 18px;
}
.tech-btn-group .btn {
border-radius: 10px;
padding: 10px 16px;
font-weight: 600;
font-size: 13px;
transition: all .2s;
}
.scanner-input {
height: 48px;
font-size: 16px;
border-radius: 10px;
border: 2px dashed #dee2e6;
text-align: center;
letter-spacing: 1.5px;
transition: border-color .2s;
}
.scanner-input:focus {
border-color: var(--tech-primary);
box-shadow: 0 0 0 .2rem rgba(255, 152, 0, .15);
}
.scan-note {
color: #6c757d;
font-size: 12px;
}
.table-tech thead th {
background: #f8f9fa;
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
letter-spacing: .4px;
color: #495057;
border-bottom: 2px solid #ffcc80;
padding: 10px 8px;
white-space: nowrap;
}
.table-tech tbody td {
padding: 8px;
vertical-align: middle;
font-size: 13px;
}
.table-tech tbody tr:hover {
background: #fff3e0;
}
.btn-sm-icon {
width: 30px;
height: 30px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 7px;
font-size: 14px;
}
.mode-section {
transition: opacity .2s;
}
.mode-section.d-none {
display: none !important;
}
.tech-modal .modal-content {
border-radius: 14px;
border: none;
}
.tech-modal .modal-header {
background: linear-gradient(135deg, var(--tech-primary), var(--tech-primary-dark));
color: #fff;
border-radius: 14px 14px 0 0;
padding: 14px 20px;
}
.teknisi-badge {
font-size: 13px;
background: #f8f9fa;
border-radius: 8px;
padding: 10px 14px;
border-left: 3px solid var(--tech-primary);
}
.teknisi-badge strong {
color: #1a1a2e;
}
/* ===========================
SCANNER (History Barang style)
=========================== */
.form-control-lg {
height: 60px;
font-size: 22px;
border-radius: 12px;
border: 2px dashed #dee2e6;
text-align: center;
letter-spacing: 1.5px;
}
.form-control:focus {
border-color: var(--tech-primary);
box-shadow: 0 0 0 .2rem rgba(255, 152, 0, .2);
}
.camera-btn {
height: 55px;
border-radius: 12px;
font-size: 17px;
}
#reader {
width: 100%;
min-height: 280px;
border-radius: 12px;
overflow: hidden;
}
#cameraArea .scan-note {
color: #6c757d;
font-size: 13px;
}
/* ===========================
CUSTOM CHECKBOX (Transfer Items style)
=========================== */
.form-check-input {
border: 2px solid #6c757d; /* border abu gelap agar terlihat saat belum dicentang */
background-color: #ffffff; /* pastikan background checkbox putih, beda dari bg website */
width: 1.1em;
height: 1.1em;
cursor: pointer;
}
.form-check-input:checked {
background-color: #0d6efd; /* warna saat dicentang (biru bootstrap, bisa diganti) */
border-color: #0d6efd;
}
.form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
border-color: #0d6efd;
}
</style>
<div class="container-fluid px-3 mt-3">
<!-- Header -->
<div class="d-flex align-items-center gap-2 mb-3">
<div class="bg-warning text-white p-2 rounded-3 d-flex align-items-center justify-content-center" style="width:38px;height:38px;">
<i class="bi bi-tools fs-5"></i>
</div>
<div>
<h5 class="mb-0 fw-bold" style="color:#1a1a2e;">Peralatan Teknisi</h5>
<small class="text-muted">Kelola barang bawaan, pengembalian, dan transfer antar teknisi</small>
</div>
</div>
<div class="row g-3">
<!-- ============================================================ -->
<!-- LEFT PANEL -->
<!-- ============================================================ -->
<div class="col-lg-5">
<div class="card tech-card">
<div class="card-header-custom d-flex align-items-center gap-2">
<i class="bi bi-box-seam"></i>
<span>Barang Teknisi</span>
</div>
<div class="card-body">
<!-- Mode Buttons -->
<div class="btn-group tech-btn-group w-100 mb-3" role="group">
<input type="radio" class="btn-check" name="mode" id="modeKembalikan" value="kembalikan">
<label class="btn btn-outline-danger" for="modeKembalikan">
<i class="bi bi-arrow-return-left me-1"></i> Dikembalikan
</label>
<input type="radio" class="btn-check" name="mode" id="modeDibawa" value="dibawa" checked>
<label class="btn btn-outline-success" for="modeDibawa">
<i class="bi bi-bag-check me-1"></i> Dibawa
</label>
<input type="radio" class="btn-check" name="mode" id="modeTransfer" value="transfer">
<label class="btn btn-outline-primary" for="modeTransfer">
<i class="bi bi-arrow-left-right me-1"></i> Ditransfer
</label>
</div>
<!-- ================================================ -->
<!-- CAMERA AREA (shared, History Barang pattern) -->
<!-- ================================================ -->
<div id="cameraArea" style="display:none;">
<div class="text-center">
<div id="reader"></div>
<small class="scan-note d-block mt-2">
Arahkan QR ID Ke Kamera.
</small>
<button type="button" class="btn btn-secondary w-100 mt-3" id="btnCloseCamera">
Tutup Kamera
</button>
</div>
</div>
<!-- ================================================ -->
<!-- MODE 1: DIKEMBALIKAN -->
<!-- ================================================ -->
<div class="mode-section d-none" id="sectionKembalikan">
<div class="text-center mb-3">
<div id="scannerAreaKembalikan">
<input type="text" id="scanKembalikan" class="form-control form-control-lg text-center"
placeholder="Scan / Input QR ID" autocomplete="off">
<small class="scan-note d-block mt-2">
Scanner akan otomatis memanggil data.
</small>
<button type="button" class="btn btn-warning w-100 camera-btn mt-4" id="btnCamKembalikan">
<i class="bi bi-camera me-1"></i>
Scan Dengan Kamera
</button>
</div>
</div>
<div class="table-responsive">
<table id="tableKembalikan" class="table table-tech table-hover table-striped align-middle w-100">
<thead>
<tr>
<th style="width:40px">No</th>
<th>Barcode</th>
<th>Nama Barang</th>
<th>Serial Number</th>
<th>Teknisi</th>
<th style="width:40px">Aksi</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<button class="btn btn-danger w-100 fw-semibold" id="btnSubmitKembalikan">
<i class="bi bi-check2-circle me-1"></i> Submit Pengembalian
</button>
</div>
<!-- ================================================ -->
<!-- MODE 2: DIBAWA -->
<!-- ================================================ -->
<div class="mode-section" id="sectionDibawa">
<div class="mb-3">
<label class="form-label fw-semibold text-muted small mb-1">Pilih Teknisi</label>
<select class="form-select" id="teknisiDibawa">
<option value="">-- Pilih Teknisi --</option>
<?php foreach ($teknisi_list as $t): ?>
<option value="<?= (int)$t->id; ?>">
<?= htmlspecialchars($t->employee_code . ' - ' . $t->full_name, ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="text-center mb-3">
<div id="scannerAreaDibawa">
<input type="text" id="scanDibawa" class="form-control form-control-lg text-center"
placeholder="Scan / Input QR ID" autocomplete="off">
<small class="scan-note d-block mt-2">
Scanner akan otomatis memanggil data.
</small>
<button type="button" class="btn btn-warning w-100 camera-btn mt-4" id="btnCamDibawa">
<i class="bi bi-camera me-1"></i>
Scan Dengan Kamera
</button>
</div>
</div>
<div class="table-responsive">
<table id="tableDibawa" class="table table-tech table-hover table-striped align-middle w-100">
<thead>
<tr>
<th style="width:40px">No</th>
<th>Barcode</th>
<th>Nama Barang</th>
<th>Serial Number</th>
<th style="width:40px">Aksi</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<button class="btn btn-success w-100 fw-semibold" id="btnSubmitDibawa">
<i class="bi bi-check2-circle me-1"></i> Submit Barang Dibawa
</button>
</div>
<!-- ================================================ -->
<!-- MODE 3: DITRANSFER -->
<!-- ================================================ -->
<div class="mode-section d-none" id="sectionTransfer">
<div class="mb-3">
<label class="form-label fw-semibold text-muted small mb-1">From Teknisi</label>
<select class="form-select" id="teknisiFrom">
<option value="">-- Pilih Teknisi Asal --</option>
<?php foreach ($teknisi_list as $t): ?>
<option value="<?= (int)$t->id; ?>">
<?= htmlspecialchars($t->employee_code . ' - ' . $t->full_name, ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="table-responsive">
<table id="tableTransferItems" class="table table-tech table-hover table-striped align-middle w-100">
<thead>
<tr>
<th style="width:40px">No</th>
<th>Barcode</th>
<th>Nama Barang</th>
<th>Serial Number</th>
<th style="width:50px" class="text-center">
<div class="d-flex align-items-center justify-content-center gap-1">
<span class="small">Aksi</span>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="checkAll">
</div>
</div>
</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="mb-3">
<label class="form-label fw-semibold text-muted small mb-1">To Teknisi</label>
<select class="form-select" id="teknisiTo">
<option value="">-- Pilih Teknisi Tujuan --</option>
<?php foreach ($teknisi_list as $t): ?>
<option value="<?= (int)$t->id; ?>">
<?= htmlspecialchars($t->employee_code . ' - ' . $t->full_name, ENT_QUOTES, 'UTF-8'); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<button class="btn btn-primary w-100 fw-semibold" id="btnSubmitTransfer">
<i class="bi bi-check2-circle me-1"></i> Submit Transfer
</button>
</div>
</div>
</div>
</div>
<!-- ============================================================ -->
<!-- RIGHT PANEL: Daftar Teknisi -->
<!-- ============================================================ -->
<div class="col-lg-7">
<div class="card tech-card">
<div class="card-header-custom d-flex align-items-center gap-2">
<i class="bi bi-people"></i>
Daftar Teknisi
</div>
<div class="card-body">
<div class="table-responsive">
<table id="tableTeknisi" class="table table-tech table-hover table-striped align-middle w-100">
<thead>
<tr>
<th style="width:50px">No</th>
<th>Nama Teknisi</th>
<th>Kode Karyawan</th>
<th>Departemen</th>
<th style="width:100px">Jumlah Item</th>
<th style="width:140px">Aksi</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ============================================================ -->
<!-- MODAL DETAIL TEKNISI -->
<!-- ============================================================ -->
<div class="modal fade tech-modal" id="modalDetailTeknisi" tabindex="-1" data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="bi bi-person-badge me-2"></i> Detail Teknisi</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<!-- Teknisi Info -->
<div class="row g-2 mb-3" id="detailTeknisiInfo">
<div class="col-md-3">
<div class="teknisi-badge">
<small class="text-muted">Nama</small><br>
<strong id="detNama">-</strong>
</div>
</div>
<div class="col-md-3">
<div class="teknisi-badge">
<small class="text-muted">Kode Karyawan</small><br>
<strong id="detKode">-</strong>
</div>
</div>
<div class="col-md-3">
<div class="teknisi-badge">
<small class="text-muted">Jabatan</small><br>
<strong id="detJabatan">-</strong>
</div>
</div>
<div class="col-md-3">
<div class="teknisi-badge">
<small class="text-muted">Departemen</small><br>
<strong id="detDepartemen">-</strong>
</div>
</div>
</div>
<h6 class="fw-bold mb-2 mt-5"><i class="bi bi-box me-1"></i> Barang Bawaan</h6>
<div class="table-responsive">
<table id="tableDetailItems" class="table table-tech table-hover table-striped align-middle w-100">
<thead>
<tr>
<th style="width:50px">No</th>
<th>Barcode</th>
<th>Nama Barang</th>
<th>Serial Number</th>
<th>Jumlah</th>
<th style="width:100px">Status</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
</div>
</div>
</div>
</div>
<!-- ============================================================ -->
<!-- MODAL FORM BARANG BAWAAN TEKNISI -->
<!-- ============================================================ -->
<div class="modal fade tech-modal" id="modalFormBarangBawaan" tabindex="-1" data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="bi bi-file-earmark-text me-2"></i> Form Barang Bawaan Teknisi</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<!-- Header Info -->
<div class="row g-2 mb-3" id="formBarangInfo">
<div class="col-md-12">
<div class="teknisi-badge">
<div class="row">
<div class="col-md-4">
<small class="text-muted">No. Faktur</small><br>
<strong id="fbNoFaktur">-</strong>
</div>
<div class="col-md-4">
<small class="text-muted">Tanggal</small><br>
<strong id="fbTanggal">-</strong>
</div>
<div class="col-md-4">
<small class="text-muted">Teknisi</small><br>
<strong id="fbTeknisi">-</strong>
</div>
</div>
</div>
</div>
</div>
<!-- Data table -->
<h6 class="fw-bold mb-2"><i class="bi bi-box me-1"></i> Barang Bawaan</h6>
<div class="table-responsive">
<table id="tableFormBarang" class="table table-tech table-hover table-striped align-middle w-100">
<thead>
<tr>
<th style="width:50px">No</th>
<th>Barcode</th>
<th>Nama Barang</th>
<th>Serial Number</th>
<th style="width:20px">Jumlah</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" id="btnCetakPDF">
<i class="bi bi-file-pdf me-1"></i> PDF
</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
</div>
</div>
</div>
</div>
<script>
let kembalikanData = [];
let dibawaData = [];
let dtKembalikan, dtDibawa, dtTransferItems, dtTeknisi, dtDetailItems;
let activeScanInput = null;
$(function(){
// =============================================================
// MODE TOGGLE
// =============================================================
$('input[name="mode"]').change(function(){
$('.mode-section').addClass('d-none');
switch ($(this).val()) {
case 'kembalikan':
$('#sectionKembalikan').removeClass('d-none');
setTimeout(() => $('#scanKembalikan').focus(), 100);
break;
case 'dibawa':
$('#sectionDibawa').removeClass('d-none');
setTimeout(() => {
$('#teknisiDibawa').select2({width:'100%',placeholder:'-- Pilih Teknisi --'});
$('#scanDibawa').focus();
}, 100);
break;
case 'transfer':
$('#sectionTransfer').removeClass('d-none');
setTimeout(() => {
$('#teknisiFrom').select2({width:'100%',placeholder:'-- Pilih Teknisi Asal --'});
$('#teknisiTo').select2({width:'100%',placeholder:'-- Pilih Teknisi Tujuan --'});
$('#teknisiFrom').off('.transfer').on('change.transfer select2:select.transfer', function(){
loadTransferItems();
});
loadTransferItems();
}, 100);
break;
}
});
$('#teknisiDibawa').select2({width:'100%',placeholder:'-- Pilih Teknisi --'});
// =============================================================
// INIT LEFT TABLES
// =============================================================
dtKembalikan = $('#tableKembalikan').DataTable({
data: kembalikanData,
columns: [
{ data: 'no' },
{ data: 'barcode' },
{ data: 'nama_barang' },
{ data: 'serial_number' },
{ data: 'teknisi' },
{ data: 'aksi', orderable: false }
],
// language: { url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json" },
pageLength: 5,
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, 'All']]
});
dtDibawa = $('#tableDibawa').DataTable({
data: dibawaData,
columns: [
{ data: 'no' },
{ data: 'barcode' },
{ data: 'nama_barang' },
{ data: 'serial_number' },
{ data: 'aksi', orderable: false }
],
// language: { url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json" },
pageLength: 5,
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, 'All']]
});
dtTransferItems = $('#tableTransferItems').DataTable({
columns: [
{ data: 0 },
{ data: 1 },
{ data: 2 },
{ data: 3 },
{
data: null,
orderable: false,
searchable: false,
className: 'text-center',
defaultContent: '',
render: function(data, type, row) {
if (type !== 'display') return data;
return '<div class="form-check"><input class="form-check-input checkbox-item" type="checkbox" data-barcode="' + row[1] + '"></div>';
}
}
],
language: {
// url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json",
emptyTable: 'Pilih teknisi asal terlebih dahulu'
},
pageLength: 5,
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, 'All']],
drawCallback: function() {
$('#tableTransferItems tbody input:checkbox:not(#checkAll)').each(function(){
let barcode = $(this).data('barcode');
if (window._checkedBarcodes && window._checkedBarcodes.indexOf(barcode) >= 0) {
$(this).prop('checked', true);
}
});
}
});
// =============================================================
// RIGHT PANEL: DAFTAR TEKNISI (server-side)
// =============================================================
dtTeknisi = $('#tableTeknisi').DataTable({
processing: true,
serverSide: true,
ajax: {
url: "<?= base_url('teknisi/get_teknisi_table'); ?>",
type: "GET"
},
columns: [
{ data: 0 },
{ data: 1 },
{ data: 2 },
{ data: 3 },
{ data: 4, className: 'text-center' },
{ data: 5, className: 'text-center', orderable: false }
],
order: [[1, 'asc']],
// language: { url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json" },
pageLength: 10,
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, 'All']]
});
// =============================================================
// MODAL DETAIL TEKNISI - Items Table (initialized on demand)
// =============================================================
$(document).on('click', '.btn-detail-teknisi', function(){
let userId = $(this).data('id');
openDetailTeknisi(userId);
});
function openDetailTeknisi(userId) {
// Reset info
$('#detNama').text('-');
$('#detKode').text('-');
$('#detJabatan').text('-');
$('#detDepartemen').text('-');
// Load teknisi info
$.get("<?= base_url('teknisi/teknisi_detail'); ?>", {user_id: userId}, function(r){
if (r) {
$('#detNama').text(r.full_name || '-');
$('#detKode').text(r.employee_code || '-');
$('#detJabatan').text(r.position_name || '-');
$('#detDepartemen').text(r.department_name || '-');
}
}, 'json');
// Init / reload items DataTable
if (dtDetailItems) {
dtDetailItems.destroy();
}
dtDetailItems = $('#tableDetailItems').DataTable({
processing: true,
serverSide: true,
ajax: {
url: "<?= base_url('teknisi/get_teknisi_items'); ?>",
type: "GET",
data: function(d) {
d.user_id = userId;
}
},
columns: [
{ data: 0 },
{ data: 1 },
{ data: 2 },
{ data: 3 },
{ data: 4 },
{ data: 5, className: 'text-center' }
],
order: [[1, 'asc']],
// language: { url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json" },
pageLength: 10,
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, 'All']]
});
$('#modalDetailTeknisi').modal('show');
}
// =============================================================
// FORM BARANG BAWAAN TEKNISI
// =============================================================
let dtFormBarang;
let _formBarangUserId = null;
$(document).on('click', '.btn-form-barang-bawaan', function(){
let userId = $(this).data('id');
let nama = $(this).data('nama');
_formBarangUserId = userId;
$('#fbNoFaktur').text('Memuat...');
$('#fbTanggal').text('-');
$('#fbTeknisi').text(nama);
$.get("<?= base_url('teknisi/get_form_barang_bawaan_data'); ?>", {user_id: userId}, function(r){
if (!r.status) {
Swal.fire({icon:'error', text:r.message});
return;
}
let d = r.data;
$('#fbNoFaktur').text(d.no_faktur);
$('#fbTanggal').text(d.tanggal);
$('#fbTeknisi').text(d.teknisi);
if (dtFormBarang) {
dtFormBarang.destroy();
}
dtFormBarang = $('#tableFormBarang').DataTable({
data: d.items,
columns: [
{ data: 'no' },
{ data: 'barcode' },
{ data: 'nama_barang' },
{ data: 'serial_number' },
{ data: 'jumlah', className: 'text-center' }
],
// language: { url: "//cdn.datatables.net/plug-ins/1.13.6/i18n/id.json" },
pageLength: 10,
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, 'All']],
order: []
});
}, 'json');
$('#modalFormBarangBawaan').modal('show');
});
$('#btnCetakPDF').click(function(){
if (_formBarangUserId) {
let url = "<?= base_url('teknisi/generate_pdf_barang_bawaan/'); ?>" + _formBarangUserId;
window.open(url, '_blank');
}
});
// =============================================================
// SCAN: MODE KEMBALIKAN
// =============================================================
$('#scanKembalikan').keypress(function(e){
if (e.which == 13) scanKembalikan();
});
let html5QrCode = null;
let lastScannerMode = null;
$('#btnCamKembalikan').click(function(){
activeScanInput = 'kembalikan';
lastScannerMode = 'kembalikan';
openScanner();
});
function openScanner() {
let mode = activeScanInput === 'kembalikan' ? 'Kembalikan' : 'Dibawa';
$('#scannerArea' + mode).hide();
$('#cameraArea').show();
if (html5QrCode) {
html5QrCode = null;
}
html5QrCode = new Html5Qrcode("reader");
html5QrCode.start(
{ facingMode: "environment" },
{ fps: 10, qrbox: 220 },
function(decodedText) {
html5QrCode.stop().then(function(){
$('#cameraArea').hide();
$('#scannerArea' + mode).show();
if (activeScanInput === 'kembalikan') {
$('#scanKembalikan').val(decodedText);
scanKembalikan();
} else {
$('#scanDibawa').val(decodedText);
scanDibawa();
}
activeScanInput = null;
});
}
);
}
$('#btnCloseCamera').click(function(){
if (html5QrCode) {
let mode = lastScannerMode === 'kembalikan' ? 'Kembalikan' : 'Dibawa';
html5QrCode.stop().then(function(){
$('#cameraArea').hide();
$('#scannerArea' + mode).show();
$('#' + (lastScannerMode === 'kembalikan' ? 'scanKembalikan' : 'scanDibawa')).focus();
activeScanInput = null;
lastScannerMode = null;
});
}
});
// Close camera when mode changes
let _modeChange = $('input[name="mode"]').change(function(){
if (html5QrCode) {
let currentMode = $(this).val();
html5QrCode.stop().then(function(){
$('#cameraArea').hide();
if (currentMode === 'kembalikan' || currentMode === 'dibawa') {
let cap = currentMode === 'kembalikan' ? 'Kembalikan' : 'Dibawa';
$('#scannerArea' + cap).show();
}
activeScanInput = null;
lastScannerMode = null;
});
}
});
function scanKembalikan() {
let barcode = $('#scanKembalikan').val().trim();
if (!barcode) return;
if (kembalikanData.some(d => d.barcode == barcode)) {
Swal.fire({icon:'warning', text:'Barcode sudah ditambahkan'});
$('#scanKembalikan').val('').focus();
return;
}
$.get("<?= base_url('teknisi/scan_item'); ?>", {barcode: barcode}, function(r){
if (!r.status) {
Swal.fire({icon:'error', text:r.message});
$('#scanKembalikan').val('').focus();
return;
}
let data = r.data;
if (!data.teknisi_name) {
Swal.fire({icon:'warning', text:'Barang tidak sedang dibawa teknisi manapun'});
$('#scanKembalikan').val('').focus();
return;
}
let teknisiText = data.teknisi_code + ' - ' + data.teknisi_name;
let no = kembalikanData.length + 1;
kembalikanData.push({
no: no,
barcode: data.barcode,
nama_barang: data.nama_barang,
serial_number: data.serial_number || '-',
teknisi: teknisiText,
aksi: '<button class="btn btn-outline-danger btn-sm-icon delete-kembalikan" data-barcode="'+data.barcode+'"><i class="bi bi-trash"></i></button>'
});
refreshTable(dtKembalikan, kembalikanData);
$('#scanKembalikan').val('').focus();
Swal.fire({icon:'success', text:'Barang ditambahkan ke daftar pengembalian', timer:1200, showConfirmButton:false});
}, 'json');
}
// =============================================================
// SCAN: MODE DIBAWA
// =============================================================
$('#scanDibawa').keypress(function(e){
if (e.which == 13) scanDibawa();
});
$('#btnCamDibawa').click(function(){
activeScanInput = 'dibawa';
lastScannerMode = 'dibawa';
openScanner();
});
function scanDibawa() {
let barcode = $('#scanDibawa').val().trim();
if (!barcode) return;
if (dibawaData.some(d => d.barcode == barcode)) {
Swal.fire({icon:'warning', text:'Barcode sudah ditambahkan'});
$('#scanDibawa').val('').focus();
return;
}
$.get("<?= base_url('teknisi/scan_item'); ?>", {barcode: barcode}, function(r){
if (!r.status) {
Swal.fire({icon:'error', text:r.message});
$('#scanDibawa').val('').focus();
return;
}
if (r.data.teknisi_name) {
Swal.fire({icon:'warning', text:'Barang sedang dibawa ' + r.data.teknisi_code + ' - ' + r.data.teknisi_name});
$('#scanDibawa').val('').focus();
return;
}
let data = r.data;
let no = dibawaData.length + 1;
dibawaData.push({
no: no,
barcode: data.barcode,
nama_barang: data.nama_barang,
serial_number: data.serial_number || '-',
aksi: '<button class="btn btn-outline-danger btn-sm-icon delete-dibawa" data-barcode="'+data.barcode+'"><i class="bi bi-trash"></i></button>'
});
refreshTable(dtDibawa, dibawaData);
$('#scanDibawa').val('').focus();
Swal.fire({icon:'success', text:'Barang ditambahkan ke daftar bawaan', timer:1200, showConfirmButton:false});
}, 'json');
}
// =============================================================
// DELETE ROWS
// =============================================================
$(document).on('click', '.delete-kembalikan', function(){
let barcode = $(this).data('barcode');
Swal.fire({
icon: 'warning',
title: 'Hapus Data?',
text: 'Yakin ingin menghapus item ini dari daftar pengembalian?',
showCancelButton: true,
confirmButtonColor: '#dc3545',
confirmButtonText: 'Ya, Hapus',
cancelButtonColor: '#6c757d',
cancelButtonText: 'Batal',
reverseButtons: true
}).then(result => {
if (!result.isConfirmed) return;
kembalikanData = kembalikanData.filter(d => d.barcode != barcode);
refreshTable(dtKembalikan, renumber(kembalikanData));
Swal.fire({icon:'success', title:'Berhasil', text:'Item berhasil dihapus dari daftar.', timer:1200, showConfirmButton:false});
});
});
$(document).on('click', '.delete-dibawa', function(){
let barcode = $(this).data('barcode');
Swal.fire({
icon: 'warning',
title: 'Hapus Data?',
text: 'Yakin ingin menghapus item ini dari daftar bawaan?',
showCancelButton: true,
confirmButtonColor: '#dc3545',
confirmButtonText: 'Ya, Hapus',
cancelButtonColor: '#6c757d',
cancelButtonText: 'Batal',
reverseButtons: true
}).then(result => {
if (!result.isConfirmed) return;
dibawaData = dibawaData.filter(d => d.barcode != barcode);
refreshTable(dtDibawa, renumber(dibawaData));
Swal.fire({icon:'success', title:'Berhasil', text:'Item berhasil dihapus dari daftar.', timer:1200, showConfirmButton:false});
});
});
// =============================================================
// LOAD TRANSFER ITEMS (on From Teknisi change)
// =============================================================
function loadTransferItems() {
let userId = $('#teknisiFrom').val();
// console.log('[loadTransferItems] userId:', userId);
if (!userId) {
dtTransferItems.clear().draw();
return;
}
let url = "<?= base_url('teknisi/get_data'); ?>";
// console.log('[loadTransferItems] GET', url, {user_id: userId, status: 'active'});
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
data: {user_id: userId, status: 'active'},
success: function(r){
// console.log('[loadTransferItems] response:', r);
let rows = r.data || [];
window._checkedBarcodes = [];
dtTransferItems.clear();
dtTransferItems.rows.add(rows).draw();
},
error: function(jqXHR, textStatus, errorThrown){
console.error('[loadTransferItems] AJAX fail:', textStatus, errorThrown, jqXHR.responseText);
Swal.fire({icon:'error', text:'Gagal memuat data barang teknisi'});
}
});
}
// Checkbox select all
$(document).on('change', '#checkAll', function(){
let checked = $(this).prop('checked');
$('#tableTransferItems tbody .checkbox-item').prop('checked', checked);
updateCheckedBarcodes();
});
$(document).on('change', '.checkbox-item', function(){
updateCheckedBarcodes();
let all = $('#tableTransferItems tbody .checkbox-item').length;
let chk = $('#tableTransferItems tbody .checkbox-item:checked').length;
$('#checkAll').prop('checked', all > 0 && all == chk);
});
function updateCheckedBarcodes() {
window._checkedBarcodes = [];
$('#tableTransferItems tbody .checkbox-item:checked').each(function(){
window._checkedBarcodes.push($(this).data('barcode'));
});
}
// =============================================================
// SUBMIT: TRANSFER
// =============================================================
$('#btnSubmitTransfer').click(function(){
let fromUserId = $('#teknisiFrom').val();
let toUserId = $('#teknisiTo').val();
if (!fromUserId) {
Swal.fire({icon:'warning', title:'Teknisi Asal', text:'Pilih teknisi asal'});
return;
}
if (!toUserId) {
Swal.fire({icon:'warning', title:'Teknisi Tujuan', text:'Pilih teknisi tujuan'});
return;
}
if (fromUserId == toUserId) {
Swal.fire({icon:'warning', title:'Sama', text:'Teknisi tujuan tidak boleh sama dengan teknisi asal'});
return;
}
let barcodes = window._checkedBarcodes || [];
if (barcodes.length == 0) {
Swal.fire({icon:'warning', title:'Tidak ada barang', text:'Pilih minimal 1 barang yang akan ditransfer'});
return;
}
Swal.fire({
title: 'Konfirmasi Transfer',
html: barcodes.length + ' barang akan ditransfer ke teknisi<br>' + ($('#teknisiTo option:selected').text() || ''),
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#007bff',
confirmButtonText: 'Ya, Transfer',
cancelButtonText: 'Batal'
}).then(result => {
if (!result.isConfirmed) return;
// console.log('[Transfer] submitting', barcodes.length, 'items, from_user:', fromUserId, 'to_user:', toUserId);
submitBatch('batch_transfer', {
barcodes: barcodes,
from_user_id: fromUserId,
to_user_id: toUserId
}, function(){
window._checkedBarcodes = [];
$('#checkAll').prop('checked', false);
loadTransferItems();
dtTeknisi.ajax.reload(null, false);
});
});
});
// =============================================================
// SUBMIT: KEMBALIKAN
// =============================================================
$('#btnSubmitKembalikan').click(function(){
if (kembalikanData.length == 0) {
Swal.fire({icon:'warning', title:'Tidak ada barang', text:'Scan minimal 1 barcode terlebih dahulu'});
return;
}
Swal.fire({
title: 'Konfirmasi Pengembalian',
text: kembalikanData.length + ' barang akan dikembalikan',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#dc3545',
confirmButtonText: 'Ya, Kembalikan',
cancelButtonText: 'Batal'
}).then(result => {
if (!result.isConfirmed) return;
let barcodes = kembalikanData.map(d => d.barcode);
// console.log('[Kembalikan] submitting', barcodes.length, 'items:', barcodes);
submitBatch('batch_kembalikan', {barcodes: barcodes}, function(){
kembalikanData = [];
refreshTable(dtKembalikan, []);
$('#scanKembalikan').focus();
dtTeknisi.ajax.reload(null, false);
});
});
});
// =============================================================
// SUBMIT: DIBAWA
// =============================================================
$('#btnSubmitDibawa').click(function(){
let userId = $('#teknisiDibawa').val();
if (!userId) {
Swal.fire({icon:'warning', title:'Pilih Teknisi', text:'Pilih teknisi terlebih dahulu'});
return;
}
if (dibawaData.length == 0) {
Swal.fire({icon:'warning', title:'Tidak ada barang', text:'Scan minimal 1 barcode terlebih dahulu'});
return;
}
Swal.fire({
title: 'Konfirmasi Penugasan',
html: dibawaData.length + ' barang akan ditugaskan ke teknisi<br>' + ($('#teknisiDibawa option:selected').text() || ''),
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#28a745',
confirmButtonText: 'Ya, Tugaskan',
cancelButtonText: 'Batal'
}).then(result => {
if (!result.isConfirmed) return;
let barcodes = dibawaData.map(d => d.barcode);
// console.log('[Dibawa] submitting', barcodes.length, 'items to user_id:', userId, 'barcodes:', barcodes);
submitBatch('batch_dibawa', {barcodes: barcodes, user_id: userId}, function(){
dibawaData = [];
refreshTable(dtDibawa, []);
$('#scanDibawa').focus();
dtTeknisi.ajax.reload(null, false);
});
});
});
// =============================================================
// UTILITY FUNCTIONS
// =============================================================
function submitBatch(endpoint, data, onSuccess) {
let mode = endpoint.replace('batch_', '');
let btnId = 'btnSubmit' + mode.charAt(0).toUpperCase() + mode.slice(1);
let btn = $('#' + btnId);
let originalText = btn.data('original-text') || btn.html();
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span> Memproses...');
// console.log('[submitBatch] endpoint:', endpoint, 'payload:', JSON.stringify(data));
$.ajax({
url: "<?= base_url('teknisi/'); ?>" + endpoint,
type: "POST",
dataType: "json",
data: data,
traditional: false,
success: function(r) {
// console.log('[submitBatch] response:', endpoint, r);
btn.prop('disabled', false).html(originalText);
if (r.status) {
Swal.fire({icon:'success', text:r.message, timer:2000, showConfirmButton:false});
if (onSuccess) onSuccess();
} else {
let errMsg = r.message;
if (r.debug) errMsg += '<br><small class="text-muted">' + r.debug + '</small>';
Swal.fire({icon:'error', html:errMsg});
}
},
error: function(jqXHR, textStatus, errorThrown) {
console.error('[submitBatch] error:', endpoint, textStatus, errorThrown, jqXHR.responseText);
btn.prop('disabled', false).html(originalText);
Swal.fire({icon:'error', text:'Terjadi kesalahan server'});
}
});
}
function refreshTable(dt, data) {
let reindexed = renumber(data);
dt.clear();
dt.rows.add(reindexed).draw();
}
function renumber(arr) {
return arr.map((d, i) => ({...d, no: i + 1}));
}
// Store original button text
$('#btnSubmitKembalikan, #btnSubmitDibawa, #btnSubmitTransfer').each(function(){
$(this).data('original-text', $(this).html());
});
});
</script>