232 lines
9.6 KiB
PHP
232 lines
9.6 KiB
PHP
@extends('layout.main')
|
||
@section('body_main')
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<div class="card">
|
||
<div class="card-header d-flex align-items-center justify-content-between">
|
||
<h4 class="mb-0">Log Aktivitas</h4>
|
||
</div>
|
||
<div class="card-body p-3">
|
||
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 mb-3 flex-wrap">
|
||
<div class="input-group input-group-sm flex-grow-1" style="max-width:320px;">
|
||
<span class="input-group-text bg-white border-end-0">
|
||
<i class="fa fa-search text-muted"></i>
|
||
</span>
|
||
<input type="search"
|
||
id="tableSearch"
|
||
class="form-control border-start-0"
|
||
placeholder="Cari nama file / nomor dokumen / aksi"
|
||
oninput="debouncedTableSearch(this.value)">
|
||
</div>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<label class="small mb-0 text-muted">Mulai</label>
|
||
<input type="date" id="startDate" class="form-control form-control-sm" onchange="applyDateFilter()">
|
||
</div>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<label class="small mb-0 text-muted">Selesai</label>
|
||
<input type="date" id="endDate" class="form-control form-control-sm" onchange="applyDateFilter()">
|
||
</div>
|
||
<div class="d-flex align-items-center gap-2">
|
||
<select id="tablePageSize" class="form-select form-select-sm" style="width: auto;">
|
||
<option value="5">5</option>
|
||
<option value="10"selected>10</option>
|
||
<option value="20">20</option>
|
||
<option value="50">50</option>
|
||
<option value="100">100</option>
|
||
</select>
|
||
</div>
|
||
<button class="btn btn-outline-secondary btn-sm" onclick="refreshLog()">
|
||
<i class="fa fa-rotate"></i> Refresh
|
||
</button>
|
||
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
|
||
</div>
|
||
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
|
||
<table class="table table-sm table-hover align-middle mb-0" id="lastUpdatedTable">
|
||
<thead>
|
||
<tr>
|
||
<th>Nama</th>
|
||
<th>Unit</th>
|
||
<th>Aktivitas</th>
|
||
<th>No Dokumen</th>
|
||
<th>Tanggal</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tableFolderLastUpdated">
|
||
<!-- data dari fetch masuk sini -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2 mt-3" id="paginationControls"></div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
@endsection
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '' };
|
||
const tbody = document.getElementById('tableFolderLastUpdated');
|
||
const paginationEl = document.getElementById('paginationControls');
|
||
const summaryEl = document.getElementById('tableSummary');
|
||
const pageSizeSelect = document.getElementById('tablePageSize');
|
||
const startDateInput = document.getElementById('startDate');
|
||
const endDateInput = document.getElementById('endDate');
|
||
|
||
if(pageSizeSelect){
|
||
const initialSize = parseInt(pageSizeSelect.value);
|
||
if(!isNaN(initialSize)) tableState.pageSize = initialSize;
|
||
pageSizeSelect.addEventListener('change', (e) => {
|
||
const val = parseInt(e.target.value);
|
||
if(!isNaN(val) && val > 0){
|
||
tableState.pageSize = val;
|
||
tableState.page = 1;
|
||
fetchData();
|
||
}
|
||
});
|
||
}
|
||
|
||
window.applyDateFilter = function(){
|
||
tableState.startDate = startDateInput.value || '';
|
||
tableState.endDate = endDateInput.value || '';
|
||
tableState.page = 1;
|
||
fetchData();
|
||
}
|
||
|
||
function buildRow(item){
|
||
let unitKerja = item.file ? item.file.split('/')[0] : '-';
|
||
let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-'
|
||
return `
|
||
<tr>
|
||
<td>${item.pegawai_nama_entry || '-'}</td>
|
||
<td>${unitKerja}</td>
|
||
<td>${item.action_type || '-'}</td>
|
||
<td>${item.no_dokumen || '-'}</td>
|
||
<td class="text-nowrap">${tanggal}</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
function formatTanggal(dateString) {
|
||
const d = new Date(dateString);
|
||
return d.toLocaleDateString('id-ID', {
|
||
day: '2-digit',
|
||
month: 'short',
|
||
year: 'numeric',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
});
|
||
}
|
||
|
||
function renderPagination(totalPages){
|
||
if(!paginationEl) return;
|
||
if(totalPages <= 1){
|
||
paginationEl.innerHTML = '';
|
||
return;
|
||
}
|
||
const maxButtons = 5;
|
||
let start = Math.max(1, tableState.page - Math.floor(maxButtons/2));
|
||
let end = Math.min(totalPages, start + maxButtons - 1);
|
||
start = Math.max(1, end - maxButtons + 1);
|
||
|
||
let buttons = '';
|
||
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${tableState.page === 1 ? 'disabled' : ''}>‹</button>`;
|
||
for(let i=start; i<=end; i++){
|
||
buttons += `<button class="btn btn-sm ${i === tableState.page ? 'btn-primary' : 'btn-outline-secondary'}" data-page="${i}">${i}</button>`;
|
||
}
|
||
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="next" ${tableState.page === totalPages ? 'disabled' : ''}>›</button>`;
|
||
|
||
paginationEl.innerHTML = `
|
||
<div class="d-flex align-items-center gap-2 flex-wrap">
|
||
<div class="btn-group" role="group">${buttons}</div>
|
||
<span class="small text-muted">Halaman ${tableState.page} dari ${totalPages}</span>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if(paginationEl){
|
||
paginationEl.addEventListener('click', (e) => {
|
||
const page = e.target.getAttribute('data-page');
|
||
if(!page) return;
|
||
if(page === 'prev' && tableState.page > 1) tableState.page--;
|
||
else if(page === 'next'){
|
||
if(tableState.page < tableState.lastPage) tableState.page++;
|
||
}else{
|
||
tableState.page = parseInt(page);
|
||
}
|
||
fetchData();
|
||
});
|
||
}
|
||
|
||
function renderTable(){
|
||
const pageData = tableState.data || [];
|
||
if(pageData.length === 0){
|
||
tbody.innerHTML = `
|
||
<tr>
|
||
<td colspan="5" class="text-center text-muted py-4">
|
||
Tidak ada data
|
||
</td>
|
||
</tr>
|
||
`;
|
||
}else{
|
||
tbody.innerHTML = pageData.map(buildRow).join('');
|
||
}
|
||
|
||
const from = tableState.total === 0 ? 0 : ((tableState.page -1) * tableState.pageSize) + 1;
|
||
const to = Math.min(((tableState.page -1) * tableState.pageSize) + pageData.length, tableState.total);
|
||
if(summaryEl){
|
||
summaryEl.textContent = tableState.total ? `Menampilkan ${from} - ${to} dari ${tableState.total} aktivitas` : 'Tidak ada data';
|
||
}
|
||
|
||
renderPagination(tableState.lastPage || 1);
|
||
}
|
||
|
||
let searchDebounce;
|
||
window.debouncedTableSearch = function(value){
|
||
clearTimeout(searchDebounce);
|
||
searchDebounce = setTimeout(() => {
|
||
tableState.search = value.trim();
|
||
tableState.page = 1;
|
||
fetchData();
|
||
}, 250);
|
||
}
|
||
|
||
window.refreshLog = function(){
|
||
tableState.search = '';
|
||
tableState.startDate = '';
|
||
tableState.endDate = '';
|
||
document.getElementById('tableSearch').value = '';
|
||
startDateInput.value = '';
|
||
endDateInput.value = '';
|
||
tableState.page = 1;
|
||
fetchData();
|
||
}
|
||
|
||
function fetchData(){
|
||
if(summaryEl) summaryEl.textContent = 'Memuat data...';
|
||
const params = new URLSearchParams({
|
||
page: tableState.page,
|
||
per_page: tableState.pageSize,
|
||
keyword: tableState.search || '',
|
||
start_date: tableState.startDate || '',
|
||
end_date: tableState.endDate || ''
|
||
});
|
||
fetch(`/datatable/log-activity?${params.toString()}`)
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
tableState.data = data?.data || [];
|
||
tableState.lastPage = data?.pagination?.last_page || 1;
|
||
tableState.total = data?.pagination?.total || 0;
|
||
renderTable();
|
||
})
|
||
.catch(err => {
|
||
console.error(err);
|
||
if(summaryEl) summaryEl.textContent = 'Gagal memuat data';
|
||
});
|
||
}
|
||
|
||
fetchData();
|
||
});
|
||
</script>
|