Files
CKB/resources/views/reports/technician.blade.php

1255 lines
48 KiB
PHP

@extends('layouts.backapp')
@section('styles')
<style>
/* Loading overlay - Modified to only cover content section */
#loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
backdrop-filter: blur(2px);
}
#loading-overlay .spinner-border {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Make content section relative for absolute positioning of overlay */
.kt-content {
position: relative;
}
/* Button loading state */
.btn.loading {
opacity: 0.7;
cursor: not-allowed;
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Table styling */
.table th {
background-color: #f8f9fa;
border-color: #dee2e6;
font-weight: 600;
color: #495057;
}
.table td {
vertical-align: middle;
}
/* Mechanic column styling */
.mechanic-column {
background-color: #f8f9fa;
min-width: 120px;
text-align: center;
}
/* Select2 styling - Fixed to prevent conflicts */
.select2-container--default .select2-selection--single {
height: 38px !important;
border: 1px solid #ced4da !important;
border-radius: 0.375rem !important;
background-color: #ffffff !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 36px !important;
padding-left: 12px !important;
color: #495057 !important;
background-color: transparent !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 36px !important;
background-color: transparent !important;
}
.select2-container--default .select2-search--dropdown .select2-search__field {
border: 1px solid #ced4da !important;
border-radius: 0.375rem !important;
background-color: #ffffff !important;
color: #495057 !important;
}
.select2-dropdown {
border: 1px solid #ced4da !important;
border-radius: 0.375rem !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
background-color: #ffffff !important;
}
.select2-container--default .select2-results__option {
background-color: #ffffff !important;
color: #495057 !important;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #007bff !important;
color: #ffffff !important;
}
.select2-container--default .select2-results__option[aria-selected=true] {
background-color: #e9ecef !important;
color: #495057 !important;
}
/* Form label styling */
.form-label {
font-weight: 600;
color: #595d6e;
margin-bottom: 8px;
font-size: 13px;
text-transform: none;
letter-spacing: normal;
display: block;
}
/* Filter buttons styling */
.filter-buttons {
display: flex;
gap: 10px;
}
.filter-buttons .btn {
white-space: nowrap;
}
/* Datepicker styling */
.datepicker {
width: 100% !important;
max-width: 100%;
}
.datepicker-dropdown {
width: auto !important;
min-width: 250px;
max-width: 300px;
}
/* Ensure input field follows parent width */
input.datepicker {
width: 100% !important;
box-sizing: border-box;
}
</style>
@endsection
@section('content')
<div class="kt-content" id="kt_content">
<div class="kt-portlet kt-portlet--mobile" id="kt_blockui_datatable">
<div class="kt-portlet__head kt-portlet__head--lg">
<div class="kt-portlet__head-label">
<h3 class="kt-portlet__head-title">
Laporan Teknisi
</h3>
</div>
<div class="kt-portlet__head-toolbar">
<div class="kt-portlet__head-actions">
<button type="button" class="btn btn-bold btn-success btn--sm" id="btn-export-excel">
Export
</button>
</div>
</div>
</div>
<div class="kt-portlet__body">
<!-- Filter Section -->
<div class="row">
<div class="col-md-3">
<div class="form-group">
<label class="form-label">Tanggal Mulai</label>
<input type="text" class="form-control datepicker" id="filter-start-date" placeholder="Tanggal awal" value="{{ date('Y-m-d', strtotime('-30 days')) }}" readonly>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label class="form-label">Tanggal Akhir</label>
<input type="text" class="form-control datepicker" id="filter-end-date" placeholder="Tanggal akhir" value="{{ date('Y-m-d') }}" readonly>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="form-label">Filter Dealer</label>
<select class="form-control select2" id="filter-dealer">
<option value="">Semua Dealer</option>
</select>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12 filter-buttons">
<button type="button" class="btn btn-primary btn-sm" id="btn-filter">
Cari
</button>
<button type="button" class="btn btn-secondary btn-sm" id="btn-reset">
Reset
</button>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<small class="form-text text-muted" id="default-dealer-info">Pilih dealer untuk memfilter data atau biarkan "Semua Dealer" untuk melihat data lengkap.</small>
</div>
</div>
{{-- Table Section --}}
<div class="table-responsive">
<table class="table table-striped table-bordered" id="report-technician-table">
<thead id="table-header">
<tr>
<th>No</th>
<th>Nama Pekerjaan</th>
<th>Kode Pekerjaan</th>
<th>Kategori</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot id="table-footer">
<tr>
<th colspan="4" class="text-center">Total</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
@endsection
@section('javascripts')
<script>
$(document).ready(function() {
// Check if jQuery and DataTable are available
if (typeof $ === 'undefined') {
console.error('jQuery is not loaded');
return;
}
if (typeof $.fn.DataTable === 'undefined') {
console.error('DataTable is not loaded');
// Show error message to user
$('body').append('<div class="alert alert-danger m-3">DataTable library tidak dimuat. Silakan refresh halaman.</div>');
return;
}
let dataTable;
let mechanics = [];
let isInitialized = false; // Flag to prevent double initialization
// Loading overlay functions - Modified to only cover content section
var showLoadingOverlay = function (message) {
const $content = $('#kt_content');
if ($("#loading-overlay").length === 0) {
$content.append(`
<div id="loading-overlay" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
">
<div class="spinner-border text-light" role="status" style="width: 3rem; height: 3rem;">
<span class="sr-only">Loading...</span>
</div>
<div class="text-light mt-3" style="font-size: 1.1rem; font-weight: 500;">${message}</div>
</div>
`);
} else {
$("#loading-overlay").show();
$("#loading-overlay .text-light:last").text(message);
}
};
var hideLoadingOverlay = function () {
$("#loading-overlay").hide();
};
// Initialize datepickers
$('.datepicker').datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
});
// Initialize Select2 for dealer dropdown
function initializeSelect2() {
console.log("Initializing Select2...");
if (typeof $.fn.select2 !== 'undefined') {
$('#filter-dealer').select2({
placeholder: 'Pilih...',
allowClear: true,
width: '100%'
});
} else {
console.warn('Select2 is not loaded, using default dropdown');
}
}
// Store original button text
$('#btn-filter').data('original-text', $('#btn-filter').html());
// Load dealers first
loadDealers();
function loadDealers() {
$.ajax({
url: '{{ route("reports.technician.dealers") }}',
type: 'GET',
success: function(response) {
console.log('Dealers response:', response);
if (response.status === 'success') {
let options = '<option value="">Semua Dealer</option>';
response.data.forEach(function(dealer) {
options += `<option value="${dealer.id}">${dealer.name} (${dealer.dealer_code})</option>`;
});
$('#filter-dealer').html(options);
console.log('Dealers loaded:', response.data.length);
// Initialize Select2 after populating options
initializeSelect2();
// Default ke "Semua Dealer" (tidak ada dealer yang terselect)
console.log('Default set to "Semua Dealer"');
$('#default-dealer-info').text('Pilih dealer untuk memfilter data atau biarkan "Semua Dealer" untuk melihat data lengkap.');
// Load initial DataTable only once
if (!isInitialized) {
console.log('Dealers loaded, initializing DataTable...');
setTimeout(function() {
initializeDataTable();
isInitialized = true;
}, 100);
}
} else {
toastr.error('Gagal memuat data dealer');
hideLoadingOverlay();
}
},
error: function() {
toastr.error('Gagal memuat data dealer');
hideLoadingOverlay();
}
});
}
function loadTechnicianData() {
console.log('loadTechnicianData called');
// Get dealer value from Select2 or regular select
let dealerId = '';
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
dealerId = $('#filter-dealer').select2('val') || '';
console.log('Using Select2 value:', dealerId);
} else {
dealerId = $('#filter-dealer').val() || '';
console.log('Using regular select value:', dealerId);
}
const startDate = $('#filter-start-date').val();
const endDate = $('#filter-end-date').val();
console.log('Date range:', { startDate, endDate });
const requestData = {
dealer_id: dealerId || '',
start_date: startDate,
end_date: endDate
};
console.log('Requesting data with params:', requestData);
$.ajax({
url: '{{ route("reports.technician.data") }}',
type: 'GET',
data: requestData,
success: function(response) {
if (response.status === 'success') {
// Validate response data
if (response.mechanics && Array.isArray(response.mechanics)) {
mechanics = response.mechanics;
} else {
console.warn('Invalid mechanics data:', response.mechanics);
mechanics = [];
}
} else {
console.error('Server returned error status:', response);
toastr.error('Gagal memuat data laporan teknisi');
}
},
error: function(xhr, status, error) {
console.error('AJAX Error occurred:');
console.error('Status:', status);
console.error('Error:', error);
console.error('Response Text:', xhr.responseText);
console.error('Status Code:', xhr.status);
console.error('Status Text:', xhr.statusText);
let errorMessage = 'Gagal memuat data laporan teknisi';
if (xhr.status === 500) {
errorMessage = 'Server error: ' + (xhr.responseText || 'Unknown error');
} else if (xhr.status === 404) {
errorMessage = 'Endpoint tidak ditemukan';
} else if (xhr.status === 403) {
errorMessage = 'Akses ditolak';
}
toastr.error(errorMessage);
},
complete: function() {
// Always reset button state and hide overlay
hideLoadingOverlay();
// Reset button state using stored original text
var $btnFilter = $('#btn-filter');
var storedText = $btnFilter.data('original-text') || 'Cari';
$btnFilter.html(storedText).prop('disabled', false).removeClass('loading');
}
});
}
function initializeDataTable() {
try {
// Destroy existing DataTable if exists and clean up
if (dataTable && typeof dataTable.destroy === 'function') {
dataTable.destroy();
dataTable = null;
}
// Clean up existing search inputs
$('#datatable-search').closest('.row').remove();
$('#simple-search').closest('.row').remove();
// Completely recreate table structure to avoid DOM conflicts
const $table = $('#report-technician-table');
$table.empty();
// Recreate basic table structure
$table.html(`
<thead id="table-header">
<tr>
<th>No</th>
<th>Nama Pekerjaan</th>
<th>Kode Pekerjaan</th>
<th>Kategori</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot id="table-footer">
<tr>
<th colspan="4" class="text-center">Total</th>
</tr>
</tfoot>
`);
// Check if DataTable is available
if (typeof $.fn.DataTable === 'undefined') {
console.error('DataTable is not loaded');
return;
}
// Check if table element exists
if ($table.length === 0) {
console.error('Table element not found');
return;
}
// Get filter values
let dealerId = '';
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
dealerId = $('#filter-dealer').select2('val') || '';
} else {
dealerId = $('#filter-dealer').val() || '';
}
const startDate = $('#filter-start-date').val();
const endDate = $('#filter-end-date').val();
// Try to initialize DataTable with Yajra DataTable
try {
// If mechanics are already available, use the complete structure
if (Array.isArray(mechanics) && mechanics.length > 0) {
updateTableStructureWithMechanics();
return;
}
dataTable = $table.DataTable({
processing: true,
serverSide: false, // We'll handle server-side manually
ajax: {
url: '{{ route("reports.technician.datatable") }}',
type: 'GET',
data: function(d) {
d.dealer_id = dealerId;
d.start_date = startDate;
d.end_date = endDate;
return d;
},
dataSrc: function(json) {
console.log('DataTable response:', json);
// Update mechanics from response
if (json.mechanics && Array.isArray(json.mechanics)) {
mechanics = json.mechanics;
console.log('Mechanics loaded:', mechanics.length);
// Update table structure with mechanic columns
setTimeout(function() {
updateTableStructureWithMechanics();
}, 100);
}
return json.data || [];
}
},
columns: [
{ data: 'DT_RowIndex', name: 'DT_RowIndex', orderable: false, searchable: false, width: '50px', className: 'text-center' },
{ data: 'work_name', name: 'work_name', orderable: true, searchable: true },
{ data: 'work_code', name: 'work_code', orderable: true, searchable: true, width: '120px' },
{ data: 'category_name', name: 'category_name', orderable: true, searchable: true, width: '150px' }
],
pageLength: -1,
lengthMenu: [],
order: [[1, 'asc']],
responsive: false,
dom: '<"row"<"col-sm-12"f>>' +
'<"row"<"col-sm-12"tr>>' +
'<"row"<"col-sm-12"i>>',
language: {
emptyTable: "Tidak ada data yang tersedia",
info: "Menampilkan _TOTAL_ entri",
infoEmpty: "Menampilkan 0 entri",
infoFiltered: "(difilter dari _MAX_ total entri)",
search: "Cari:",
zeroRecords: "Tidak ditemukan data yang sesuai",
processing: "Memuat data..."
},
initComplete: function() {
try {
var api = this.api();
console.log('DataTable initialization complete');
console.log('Data rows:', api.data().length);
console.log('Mechanics count:', mechanics.length);
if (api.data().length === 0) {
toastr.info('Tidak ada data yang ditemukan untuk filter yang dipilih. Silakan coba filter yang berbeda.');
}
// Enable filter button di sini!
var $btnFilter = $('#btn-filter');
var storedText = $btnFilter.data('original-text') || 'Cari';
$btnFilter.html(storedText).prop('disabled', false).removeClass('loading');
hideLoadingOverlay();
} catch (error) {
console.error('Error in initComplete:', error);
hideLoadingOverlay();
}
},
drawCallback: function() {
try {
// Update totals in footer
updateTableTotals();
} catch (error) {
console.error('Error in drawCallback:', error);
}
}
});
console.log('DataTable initialized successfully');
} catch (dataTableError) {
console.error('DataTable initialization failed:', dataTableError);
toastr.error('Gagal memuat tabel data');
hideLoadingOverlay();
}
} catch (error) {
console.error('Error in initializeDataTable:', error);
toastr.error('Gagal memuat tabel data');
hideLoadingOverlay();
}
}
function createFallbackTable(data) {
try {
// Clean up existing search inputs
$('#datatable-search').closest('.row').remove();
$('#simple-search').closest('.row').remove();
// Ensure DataTable is destroyed
if (dataTable && typeof dataTable.destroy === 'function') {
dataTable.destroy();
dataTable = null;
}
const $table = $('#report-technician-table');
$table.empty();
if (data.length > 0) {
let tableHtml = '<thead><tr>';
tableHtml += '<th>No</th><th>Nama Pekerjaan</th><th>Kode Pekerjaan</th><th>Kategori</th>';
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.name) {
tableHtml += `<th>${mechanic.name}</th>`;
}
});
}
tableHtml += '</tr></thead><tbody>';
data.forEach(function(item, index) {
tableHtml += `<tr>
<td>${index + 1}</td>
<td>${item.work_name || ''}</td>
<td>${item.work_code || ''}</td>
<td>${item.category_name || ''}</td>
`;
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
tableHtml += `<td>${item[`mechanic_${mechanic.id}_total`] || 0}</td>`;
}
});
}
tableHtml += '</tr>';
});
tableHtml += '</tbody>';
$table.html(tableHtml);
// Add simple search functionality to fallback table
addSimpleSearch($table);
} else {
$table.html('<tbody><tr><td colspan="100%" class="text-center">Tidak ada data yang tersedia untuk filter yang dipilih</td></tr></tbody>');
}
console.log('Fallback table created successfully');
hideLoadingOverlay();
} catch (fallbackError) {
console.error('Error creating fallback table:', fallbackError);
toastr.error('Gagal memuat tabel data. Silakan refresh halaman.');
hideLoadingOverlay();
}
}
function addMechanicColumns(api) {
if (!Array.isArray(mechanics) || mechanics.length === 0) {
console.log('No mechanics to add columns for');
return;
}
try {
console.log('Adding mechanic columns for', mechanics.length, 'mechanics');
// Instead of adding columns dynamically, we'll update the table structure
// and reinitialize the DataTable with the complete column configuration
updateTableStructureWithMechanics();
} catch (error) {
console.error('Error adding mechanic columns:', error);
}
}
function updateTableStructureWithMechanics() {
try {
// Destroy existing DataTable
if (dataTable && typeof dataTable.destroy === 'function') {
dataTable.destroy();
dataTable = null;
}
const $table = $('#report-technician-table');
$table.empty();
// Build header rows
let headerRow1 = `
<tr>
<th>No</th>
<th>Nama Pekerjaan</th>
<th>Kode Pekerjaan</th>
<th>Kategori</th>
`;
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
headerRow1 += `<th class="mechanic-column" style="text-align: center; background-color: #f8f9fa;"><strong>${mechanic.name}</strong></th>`;
});
}
headerRow1 += `</tr>`;
// Set thead
$table.append(`<thead id="table-header">${headerRow1}</thead>`);
$table.append('<tbody></tbody>');
// Build footer
let footerHtml = '<tr><th colspan="4" class="text-center"><strong>Total</strong></th>';
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function() {
footerHtml += `<th class="text-center mechanic-column"><strong>0</strong></th>`;
});
}
footerHtml += '</tr>';
$table.append(`<tfoot id="table-footer">${footerHtml}</tfoot>`);
// Reinitialize DataTable
initializeDataTableWithMechanics();
} catch (error) {
console.error('Error updating table structure:', error);
hideLoadingOverlay();
}
}
function initializeDataTableWithMechanics() {
try {
// Get filter values
let dealerId = '';
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
dealerId = $('#filter-dealer').select2('val') || '';
} else {
dealerId = $('#filter-dealer').val() || '';
}
const startDate = $('#filter-start-date').val();
const endDate = $('#filter-end-date').val();
// Build complete column configuration
const columns = [
{ data: 'DT_RowIndex', name: 'DT_RowIndex', orderable: false, searchable: false, width: '50px', className: 'text-center' },
{ data: 'work_name', name: 'work_name', orderable: true, searchable: true },
{ data: 'work_code', name: 'work_code', orderable: true, searchable: true, width: '120px' },
{ data: 'category_name', name: 'category_name', orderable: true, searchable: true, width: '150px' }
];
// Add mechanic columns
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
columns.push({
data: `mechanic_${mechanic.id}_total`,
name: `mechanic_${mechanic.id}_total`,
title: `${mechanic.name || 'Unknown'}`,
orderable: false,
searchable: false,
className: 'text-center mechanic-column',
defaultContent: '0'
});
}
});
}
// Initialize DataTable with complete configuration
dataTable = $('#report-technician-table').DataTable({
processing: true,
serverSide: false,
ajax: {
url: '{{ route("reports.technician.datatable") }}',
type: 'GET',
data: function(d) {
d.dealer_id = dealerId;
d.start_date = startDate;
d.end_date = endDate;
return d;
},
dataSrc: function(json) {
console.log('DataTable response:', json);
// Update mechanics from response
if (json.mechanics && Array.isArray(json.mechanics)) {
mechanics = json.mechanics;
}
return json.data || [];
}
},
columns: columns,
pageLength: -1,
lengthMenu: [],
order: [[1, 'asc']],
responsive: false,
dom: '<"row"<"col-sm-12"f>>' +
'<"row"<"col-sm-12"tr>>' +
'<"row"<"col-sm-12"i>>',
language: {
emptyTable: "Tidak ada data yang tersedia",
info: "Menampilkan _TOTAL_ entri",
infoEmpty: "Menampilkan 0 entri",
infoFiltered: "(difilter dari _MAX_ total entri)",
search: "Cari:",
zeroRecords: "Tidak ditemukan data yang sesuai",
processing: "Memuat data..."
},
initComplete: function() {
try {
var api = this.api();
console.log('DataTable with mechanics initialization complete');
console.log('Data rows:', api.data().length);
console.log('Mechanics count:', mechanics.length);
if (api.data().length === 0) {
toastr.info('Tidak ada data yang ditemukan untuk filter yang dipilih. Silakan coba filter yang berbeda.');
} else {
// Update totals after initialization
setTimeout(function() {
updateTableTotals();
}, 200);
}
// Enable filter button di sini!
var $btnFilter = $('#btn-filter');
var storedText = $btnFilter.data('original-text') || 'Cari';
$btnFilter.html(storedText).prop('disabled', false).removeClass('loading');
hideLoadingOverlay();
} catch (error) {
console.error('Error in initComplete:', error);
hideLoadingOverlay();
}
},
drawCallback: function() {
try {
console.log('DataTable drawCallback triggered');
// Add a small delay to ensure data is fully rendered
setTimeout(function() {
updateTableTotals();
}, 100);
} catch (error) {
console.error('Error in drawCallback:', error);
}
}
});
console.log('DataTable with mechanics initialized successfully');
} catch (error) {
console.error('Error initializing DataTable with mechanics:', error);
toastr.error('Gagal memuat tabel data');
hideLoadingOverlay();
}
}
function updateTableTotals() {
if (!dataTable) {
console.log('DataTable not initialized');
return;
}
try {
// Get DataTable API - try multiple methods
let api = null;
// Method 1: Direct API access
if (dataTable && typeof dataTable.api === 'function') {
api = dataTable.api();
console.log('Using dataTable.api() method');
}
// Method 2: jQuery DataTable API
else if (dataTable && typeof dataTable.dataTable === 'function') {
api = dataTable.dataTable().api();
console.log('Using dataTable.dataTable().api() method');
}
// Method 3: Direct access to DataTable instance
else if (dataTable && dataTable.api) {
api = dataTable.api;
console.log('Using direct dataTable.api access');
}
// Method 4: Try to get from jQuery element
else if ($('#report-technician-table').dataTable) {
api = $('#report-technician-table').dataTable().api();
console.log('Using jQuery element dataTable().api() method');
}
if (!api) {
console.warn('Cannot access DataTable API - trying alternative method');
// Alternative: Get data directly from table rows
updateTableTotalsFromDOM();
return;
}
console.log('DataTable API accessed successfully');
const data = api.data().toArray();
console.log('Data rows found:', data.length);
if (data.length === 0) {
console.log('No data rows found');
return;
}
// Calculate totals for each mechanic
const totals = {};
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
totals[`mechanic_${mechanic.id}_total`] = 0;
}
});
}
// Sum up values from all rows
data.forEach(function(row, index) {
console.log(`Row ${index}:`, row);
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
const value = parseInt(row[`mechanic_${mechanic.id}_total`] || 0);
totals[`mechanic_${mechanic.id}_total`] += value;
console.log(`Mechanic ${mechanic.name}: adding ${value}, total now: ${totals[`mechanic_${mechanic.id}_total`]}`);
}
});
}
});
console.log('Calculated totals:', totals);
// Update footer with totals
const $footer = $('#table-footer tr');
if ($footer.length > 0) {
let footerHtml = '<th colspan="4" class="text-center"><strong>Total</strong></th>';
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
const total = totals[`mechanic_${mechanic.id}_total`] || 0;
footerHtml += `<th class="text-center mechanic-column"><strong>${total}</strong></th>`;
}
});
}
$footer.html(footerHtml);
console.log('Footer updated successfully');
} else {
console.warn('Footer row not found');
}
} catch (error) {
console.error('Error updating table totals:', error);
// Fallback to DOM method
updateTableTotalsFromDOM();
}
}
function updateTableTotalsFromDOM() {
try {
console.log('Using DOM method to calculate totals');
// Calculate totals for each mechanic
const totals = {};
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
totals[`mechanic_${mechanic.id}_total`] = 0;
}
});
}
// Get data from table rows directly
const $rows = $('#report-technician-table tbody tr');
console.log('Found table rows:', $rows.length);
$rows.each(function(index) {
const $row = $(this);
const $cells = $row.find('td');
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic, mechanicIndex) {
if (mechanic && mechanic.id) {
// Skip first 4 columns (No, Nama Pekerjaan, Kode Pekerjaan, Kategori)
const cellIndex = 4 + mechanicIndex;
const $cell = $cells.eq(cellIndex);
const value = parseInt($cell.text() || 0);
totals[`mechanic_${mechanic.id}_total`] += value;
console.log(`Row ${index}, Mechanic ${mechanic.name}: cell ${cellIndex} = ${value}, total now: ${totals[`mechanic_${mechanic.id}_total`]}`);
}
});
}
});
console.log('DOM calculated totals:', totals);
// Update footer with totals
const $footer = $('#table-footer tr');
if ($footer.length > 0) {
let footerHtml = '<th colspan="4" class="text-center"><strong>Total</strong></th>';
if (Array.isArray(mechanics) && mechanics.length > 0) {
mechanics.forEach(function(mechanic) {
if (mechanic && mechanic.id) {
const total = totals[`mechanic_${mechanic.id}_total`] || 0;
footerHtml += `<th class="text-center mechanic-column"><strong>${total}</strong></th>`;
}
});
}
$footer.html(footerHtml);
console.log('DOM Footer updated successfully');
}
} catch (error) {
console.error('Error in DOM method:', error);
}
}
function addSimpleSearch($table) {
// Add search input above table
const searchHtml = `
<div class="row mb-3">
<div class="col-sm-12">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="fa fa-search"></i>
</span>
</div>
<input type="text" class="form-control" id="simple-search" placeholder="Cari data...">
</div>
</div>
</div>
`;
$table.before(searchHtml);
// Add search functionality
$('#simple-search').on('keyup', function() {
const searchTerm = $(this).val().toLowerCase();
$table.find('tbody tr').each(function() {
const rowText = $(this).text().toLowerCase();
if (rowText.includes(searchTerm)) {
$(this).show();
} else {
$(this).hide();
}
});
});
}
// Filter button click - Fixed button state management
$('#btn-filter').on('click', function() {
console.log('Filter button clicked');
// Prevent multiple clicks
var filterButton = $('#btn-filter');
if (filterButton.hasClass('loading') || filterButton.prop('disabled')) {
console.log('Button already loading or disabled, ignoring click');
return; // Already processing
}
// Get dealer value from Select2 or regular select
let selectedDealer = '';
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
selectedDealer = $('#filter-dealer').select2('val') || '';
} else {
selectedDealer = $('#filter-dealer').val();
}
console.log('Selected dealer:', selectedDealer);
// Show warning if user selects "Semua Dealer"
if (selectedDealer === '') {
if (!confirm('Memilih "Semua Dealer" akan memuat data yang lebih besar dan mungkin memakan waktu lebih lama. Lanjutkan?')) {
return; // User cancelled
}
}
console.log('Filter button clicked - starting data load');
// Store the original button text before changing it
var originalText = filterButton.html();
filterButton.data('original-text', originalText);
// Show loading state
filterButton.addClass('loading').prop('disabled', true);
filterButton.html('<i class="fa fa-spinner fa-spin"></i> Mencari...');
console.log('Button loading state set, original text:', originalText);
console.log('Button disabled state:', filterButton.prop('disabled'));
console.log('Button loading class:', filterButton.hasClass('loading'));
// Show loading overlay
showLoadingOverlay("Memuat data laporan teknisi...");
// Reload DataTable
if (dataTable && typeof dataTable.destroy === 'function') {
dataTable.destroy();
dataTable = null;
}
// Reset initialization flag to allow re-initialization
isInitialized = false;
// Ambil mechanics terbaru dari endpoint filter
let dealerId = '';
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
dealerId = $('#filter-dealer').select2('val') || '';
} else {
dealerId = $('#filter-dealer').val();
}
const startDate = $('#filter-start-date').val();
const endDate = $('#filter-end-date').val();
$.ajax({
url: '{{ route("reports.technician.data") }}',
type: 'GET',
data: { dealer_id: dealerId, start_date: startDate, end_date: endDate },
success: function(response) {
if (response.status === 'success' && Array.isArray(response.mechanics)) {
mechanics = response.mechanics;
updateTableStructureWithMechanics(); // DataTable akan rebuild dengan mechanics baru
} else {
initializeDataTable(); // fallback
}
},
error: function() {
initializeDataTable();
}
});
});
// Export button click
$('#btn-export-excel').on('click', function() {
exportToExcel();
});
// Reset button click
$('#btn-reset').on('click', function() {
console.log('Reset button clicked');
// Reset dealer selection
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
$('#filter-dealer').val('').trigger('change');
} else {
$('#filter-dealer').val('');
}
// Reset date inputs
$('#filter-start-date').val('{{ date('Y-m-d', strtotime('-30 days')) }}');
$('#filter-end-date').val('{{ date('Y-m-d') }}');
console.log('Filters reset, reloading DataTable...');
// Reset initialization flag
isInitialized = false;
// Show loading overlay
showLoadingOverlay("Memuat data laporan teknisi...");
if (dataTable && typeof dataTable.destroy === 'function') {
dataTable.destroy();
dataTable = null;
}
// Ambil mechanics terbaru dari endpoint data reset
let dealerId = '';
const startDate = $('#filter-start-date').val();
const endDate = $('#filter-end-date').val();
$.ajax({
url: '{{ route("reports.technician.data") }}',
type: 'GET',
data: { dealer_id: dealerId, start_date: startDate, end_date: endDate },
success: function(response) {
if (response.status === 'success' && Array.isArray(response.mechanics)) {
mechanics = response.mechanics;
updateTableStructureWithMechanics();
} else {
initializeDataTable();
}
},
error: function() {
initializeDataTable();
}
});
});
function exportToExcel() {
// Prevent multiple clicks
var exportButton = $('#btn-export-excel');
if (exportButton.hasClass('loading')) {
return; // Already processing
}
// Get dealer value from Select2 or regular select
let dealerId = '';
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
dealerId = $('#filter-dealer').select2('val') || '';
} else {
dealerId = $('#filter-dealer').val();
}
const startDate = $('#filter-start-date').val();
const endDate = $('#filter-end-date').val();
let url = '{{ route("reports.technician.export") }}';
let params = [];
if (dealerId) {
params.push('dealer_id=' + dealerId);
}
if (startDate) {
params.push('start_date=' + startDate);
}
if (endDate) {
params.push('end_date=' + endDate);
}
if (params.length > 0) {
url += '?' + params.join('&');
}
// Show loading state
exportButton.addClass('loading').prop('disabled', true);
var originalHtml = exportButton.html();
exportButton.html('<i class="fa fa-spinner fa-spin"></i> Exporting...');
// Open in new window
let newWindow = window.open(url, '_blank');
// Reset button and hide overlay after a delay
setTimeout(function() {
exportButton.removeClass('loading').prop('disabled', false).html(originalHtml);
hideLoadingOverlay();
}, 2000);
}
// Make exportToExcel available globally
window.exportToExcel = exportToExcel;
// Cleanup loading overlay on page unload
$(window).on('beforeunload', function() {
hideLoadingOverlay();
});
// Cleanup Select2 on page unload
$(window).on('beforeunload', function() {
if (typeof $.fn.select2 !== 'undefined' && $('#filter-dealer').data('select2')) {
$('#filter-dealer').select2('destroy');
}
});
// Fallback for toastr if not available
if (typeof toastr === 'undefined') {
window.toastr = {
success: function(msg) { console.log('SUCCESS:', msg); },
error: function(msg) { console.log('ERROR:', msg); },
warning: function(msg) { console.log('WARNING:', msg); },
info: function(msg) { console.log('INFO:', msg); }
};
}
});
</script>
@endsection