diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 1334370..55d4e56 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -295,18 +295,21 @@ class DashboardController extends Controller $zipName = 'files_' . time() . '.zip'; $zipPath = public_path('zip/' . $zipName); $zip = new ZipArchive; + $tempFiles = []; if($zip->open($zipPath, ZipArchive::CREATE) === TRUE){ foreach ($paths as $path) { $fullPath = public_path('file/' . $path); - if(file_exists($fullPath)){ - $relativePathInZip = $path; - $zip->addFile($fullPath, $relativePathInZip); - }else{ + if(!file_exists($fullPath)){ throw new \Exception("File tidak ditemukan: " . $path); } + + $relativePathInZip = $path; + $fileToAdd = $this->prepareFileWithWatermark($fullPath, $tempFiles); + $zip->addFile($fileToAdd, $relativePathInZip); } $zip->close(); } + $this->cleanupTempFiles($tempFiles); return response()->download(public_path('zip/' . $zipName))->deleteFileAfterSend(true); //code... } catch (\Throwable $th) { @@ -333,18 +336,21 @@ class DashboardController extends Controller $zipName = 'files_' . time() . '.zip'; $zipPath = public_path('zip/' . $zipName); $zip = new ZipArchive; + $tempFiles = []; if($zip->open($zipPath, ZipArchive::CREATE) === TRUE){ foreach ($data as $path) { $fullPath = public_path('file/' . $path); - if(file_exists($fullPath)){ - $relativePathInZip = $path; - $zip->addFile($fullPath, $relativePathInZip); - }else{ + if(!file_exists($fullPath)){ throw new \Exception("File tidak ditemukan: " . $path); } + + $relativePathInZip = $path; + $fileToAdd = $this->prepareFileWithWatermark($fullPath, $tempFiles); + $zip->addFile($fileToAdd, $relativePathInZip); } $zip->close(); } + $this->cleanupTempFiles($tempFiles); return response()->download(public_path('zip/' . $zipName))->deleteFileAfterSend(true); } catch (\Throwable $th) { return response()->json([ @@ -370,10 +376,27 @@ class DashboardController extends Controller } public function dataDocumentLast(){ - $perPage = request('per_page', 10); + $perPage = (int) request('per_page', 10); + $authUnitId = auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->objectunitkerjapegawaifk; + $keyword = request('keyword'); + $data = FileDirectory::where('statusenabled', true) + ->where(function ($query) use ($authUnitId) { + $query->where('permission_file', true) + ->orWhere(function ($sub) use ($authUnitId) { + $sub->where('permission_file', false) + ->where('id_unit_kerja', $authUnitId); + }); + }) + ->when($keyword, function ($q) use ($keyword) { + $q->where(function ($sub) use ($keyword) { + $sub->where('file', 'ILIKE', "%{$keyword}%") + ->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%"); + }); + }) ->orderBy('entry_at', 'desc') ->paginate($perPage); + $payload = [ 'status' => true, 'message' => 'Berhasil mendapatkan data', @@ -381,7 +404,10 @@ class DashboardController extends Controller 'pagination' => [ 'current_page' => $data->currentPage(), 'next_page' => $data->hasMorePages() ? $data->currentPage() + 1 : null, - 'has_more' => $data->hasMorePages() + 'has_more' => $data->hasMorePages(), + 'last_page' => $data->lastPage(), + 'per_page' => $data->perPage(), + 'total' => $data->total(), ] ]; return response()->json($payload); @@ -391,10 +417,16 @@ class DashboardController extends Controller DB::connection('dbDirectory')->beginTransaction(); try { $datas = request('data'); - foreach ($datas as $data) { + foreach ($datas as $index => $data) { list($id_unit_kerja, $nama_unit_kerja) = explode('/', $data['id_unit_kerja'],2); list($id_sub_unit_kerja, $nama_sub_unit_kerja) = explode('/', $data['id_sub_unit_kerja'],2); list($master_kategori_directory_id, $nama_kategori) = explode('/', $data['master_kategori_directory_id'],2); + + $uploadedFile = request()->file("data.$index.file"); + if(!$uploadedFile){ + throw new \RuntimeException('File wajib diunggah pada baris ke-' . ($index+1)); + } + $payload = [ 'id_unit_kerja' => $id_unit_kerja, 'id_sub_unit_kerja' => $id_sub_unit_kerja, @@ -403,16 +435,16 @@ class DashboardController extends Controller 'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap ?? null, 'tanggal_terbit' => $data['date_active'] ?? null, 'no_dokumen' => $data['no_dokumen'] ?? null, - 'permission_file' => $data['is_permission'] === "1" ? true : false, + 'permission_file' => ($data['is_permission'] ?? null) == "1", ]; - if(!empty($data['file'])){ - $file = $data['file']; - $imageName = $file->getClientOriginalName(); - $path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}"; - $file->storeAs($path, $imageName, 'file_directory'); - $payload['file'] =$path .'/' .$imageName; - } + + $imageName = $uploadedFile->getClientOriginalName(); + $path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}"; + $uploadedFile->storeAs($path, $imageName, 'file_directory'); + $payload['file'] =$path .'/' .$imageName; + $fd = FileDirectory::create($payload); + $payloadLog = [ 'file_directory_id' => $fd->file_directory_id, 'pegawai_id_entry' => $fd->pegawai_id_entry, @@ -513,6 +545,71 @@ class DashboardController extends Controller ]); } + /** + * Generate watermarked PDF to temp file (or return original) for zipping. + */ + private function prepareFileWithWatermark(string $fullPath, array &$tempFiles = []) + { + $stampFile = public_path('assets/copy.png'); + $ext = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION)); + + if ($ext !== 'pdf' || !file_exists($stampFile)) { + return $fullPath; + } + + $tempDir = storage_path('app/temp'); + if (!is_dir($tempDir)) { + @mkdir($tempDir, 0777, true); + } + $tempOut = $tempDir . '/' . uniqid('wm_') . '.pdf'; + + try { + $this->watermarkCenterToFile($fullPath, $stampFile, $tempOut); + } catch (\Throwable $e) { + // fallback convert then watermark + $converted = $tempDir . '/' . uniqid('conv_') . '.pdf'; + $this->convertWithGhostscript($fullPath, $converted); + $this->watermarkCenterToFile($converted, $stampFile, $tempOut); + $tempFiles[] = $converted; + } + + $tempFiles[] = $tempOut; + return $tempOut; + } + + private function watermarkCenterToFile(string $pdfPath, string $stampFile, string $outputPath): void + { + $pdf = new Fpdi(); + $pageCount = $pdf->setSourceFile($pdfPath); + + for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) { + $tplId = $pdf->importPage($pageNo); + $size = $pdf->getTemplateSize($tplId); + + $pdf->AddPage($size['orientation'], [$size['width'], $size['height']]); + $pdf->useTemplate($tplId); + + $stampW = $size['width'] * 0.60; + $stampH = $stampW * 0.75; + + $x = ($size['width'] - $stampW) / 2; + $y = ($size['height'] - $stampH) / 2; + + $pdf->Image($stampFile, $x, $y, $stampW, $stampH); + } + + $pdf->Output($outputPath, 'F'); + } + + private function cleanupTempFiles(array $tempFiles): void + { + foreach ($tempFiles as $file) { + if (is_string($file) && file_exists($file)) { + @unlink($file); + } + } + } + private function convertWithGhostscript(string $inputPdf, string $outputPdf): void { $gs = config('services.ghostscript.path'); @@ -530,4 +627,78 @@ class DashboardController extends Controller throw new \RuntimeException('Convert Ghostscript gagal (code=' . $code . ')'); } } + + public function recapData(){ + try { + $perPage = (int) request('per_page', 10); + $page = max(1, (int) request('page', 1)); + $keyword = strtolower(request('keyword', '')); + + $rows = FileDirectory::where('statusenabled', true)->pluck('file'); + + $grouped = []; + foreach ($rows as $path) { + $parts = array_values(array_filter(explode('/', $path))); + if(count($parts) < 4){ + continue; + } + + $unit = $parts[0]; + $folder = $parts[1]. '/' . $parts[2]; + if($keyword){ + $hit = str_contains(strtolower($unit), $keyword) || str_contains(strtolower($folder), $keyword); + if(!$hit) continue; + } + if(!isset($grouped[$unit])){ + $grouped[$unit] = []; + } + if (!isset($grouped[$unit][$folder])) { + $grouped[$unit][$folder] = 0; + } + $grouped[$unit][$folder]++; + } + $result = []; + foreach ($grouped as $unitName => $folders) { + $data = []; + foreach ($folders as $folder => $count) { + $data[] = [ + 'folder'=> $folder, + 'count' => $count, + ]; + } + + usort($data, fn($a, $b) => $b['count'] <=> $a['count']); + $result[] = [ + 'unit' => $unitName, + 'data' => $data, + ]; + } + // paginate manually + $total = count($result); + $chunks = array_chunk($result, $perPage); + $currentData = $chunks[$page-1] ?? []; + + return response()->json([ + 'status' => true, + 'data' => $currentData, + 'message' => 'Berhasil mendapatkan data', + 'pagination' => [ + 'current_page' => $page, + 'per_page' => $perPage, + 'total' => $total, + 'last_page' => max(1, ceil($total / $perPage)), + 'has_more' => $page < max(1, ceil($total / $perPage)), + ] + ]); + } catch (\Throwable $th) { + return response()->json([ + 'status' => false, + 'message' => 'Gagal! mendapatkan data' + ]); + } + } + + public function recapView(){ + return view('dashboard.recap', ['title' => 'Rekap Dokumen']); + } } diff --git a/app/Http/Controllers/LogActivityController.php b/app/Http/Controllers/LogActivityController.php new file mode 100644 index 0000000..b64c7d2 --- /dev/null +++ b/app/Http/Controllers/LogActivityController.php @@ -0,0 +1,67 @@ + 'Log Activity' + ]; + return view('logActivity.index', $data); + } + + public function datatable(){ + $perPage = (int) request('per_page', 10); + $keyword = request('keyword'); + $start = request('start_date'); + $end = request('end_date'); + + $query = LogActivity::query() + ->orderBy('entry_at','desc'); + + if($keyword){ + $query->where(function($q) use ($keyword){ + $q->where('pegawai_nama_entry', 'ILIKE', "%{$keyword}%") + ->orWhere('action_type', 'ILIKE', "%{$keyword}%") + ->orWhere('file', 'ILIKE', "%{$keyword}%") + ->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%"); + }); + } + + if($start){ + $query->whereDate('entry_at','>=',$start); + } + if($end){ + $query->whereDate('entry_at','<=',$end); + } + + $paginated = $query->paginate($perPage); + $data = $paginated->getCollection()->map(function($item){ + return [ + 'pegawai_nama_entry' => $item->pegawai_nama_entry, + 'action_type' => $item->action_type, + 'file' => $item->file, + 'no_dokumen' => $item->no_dokumen ?? $item->fileDirectory->no_dokumen ?? '-', + 'entry_at' => $item->entry_at, + 'unit_name' => $item->unit_name ?? '-', + ]; + }); + + return response()->json([ + 'status' => true, + 'data' => $data, + 'pagination' => [ + 'current_page' => $paginated->currentPage(), + 'next_page' => $paginated->hasMorePages() ? $paginated->currentPage() + 1 : null, + 'has_more' => $paginated->hasMorePages(), + 'last_page' => $paginated->lastPage(), + 'per_page' => $paginated->perPage(), + 'total' => $paginated->total(), + ] + ]); + } +} diff --git a/app/Models/LogActivity.php b/app/Models/LogActivity.php index 8e50b20..b3e9eec 100644 --- a/app/Models/LogActivity.php +++ b/app/Models/LogActivity.php @@ -11,4 +11,9 @@ class LogActivity extends Model public $timestamps = false; protected $primaryKey = 'id'; protected $guarded = ['id']; + + // public function unitKerja(){ + // return $this->belongsTo(UnitKerja::class, 'id_unit_kerja', 'id'); + // } + } diff --git a/public/js/dashboard/action.js b/public/js/dashboard/action.js index 3cfe60f..6a36ec5 100644 --- a/public/js/dashboard/action.js +++ b/public/js/dashboard/action.js @@ -1,4 +1,3 @@ - let allFiles = []; document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll(".file-input").forEach(input => { bindFileUpload(input); @@ -6,72 +5,40 @@ }); function bindFileUpload(input) { - const dropArea = input.closest(".file-drop-area"); - const fileNameBox = dropArea.querySelector(".file-name"); - const inputId = input?.id; - allFiles[inputId] = []; + const fileNameBox = input.closest(".border")?.querySelector(".file-name") || input.closest(".file-drop-area")?.querySelector(".file-name"); input.addEventListener("change", function () { - for (let i = 0; i < this.files.length; i++) { - allFiles[inputId].push(this.files[i]); - } - renderFileList(inputId, fileNameBox); - this.value = ""; // reset agar bisa pilih file lagi + if (!fileNameBox) return; + const file = this.files[0]; + if (file) { + fileNameBox.textContent = `✔ ${file.name}`; + fileNameBox.classList.remove("d-none"); + } else { + fileNameBox.textContent = ''; + fileNameBox.classList.add("d-none"); + } }); } - function renderFileList(inputId, container) { - const files = allFiles[inputId]; - if (!files || files.length === 0) { - container.classList.add("d-none"); - container.innerHTML = ""; - return; - } - - let list = ""; - - container.innerHTML = list; - container.classList.remove("d-none"); - } - - function removeFile(inputId, index) { - allFiles[inputId].splice(index, 1); - const container = document.querySelector(`#${inputId}`).closest(".file-drop-area").querySelector(".file-name"); - renderFileList(inputId, container); + function resetCreateForm(){ + colCount = 1; + $("#col_add_file").html(''); + formCreate[0]?.reset(); + formCreate.find('select').val(null).trigger('change'); + formCreate.find('input[type="file"]').val(''); + formCreate.find('.file-name').addClass('d-none').text(''); + formCreate.find('input[type="radio"]').prop('checked', false); + // rebind initial input + document.querySelectorAll(".file-input").forEach(bindFileUpload); } formCreate.off('submit').on('submit', function(e){ e.preventDefault(); const submitBtn = $(this).find('button[type="submit"]'); submitBtn.prop('disabled', true).text('menyimpan...') - let hasFile = Object.keys(allFiles).every(id => { - console.log('fil ' , allFiles[id],' length', allFiles[id].length > 0); - return Array.isArray(allFiles[id]) && allFiles[id].length > 0; - }); - if(!hasFile){ - Swal.fire({ - icon: 'warning', - title: 'Perhatian', - text: 'Silahkan upload minimal 1 file sebelum submit' - }); - submitBtn.prop('disabled', false).text('Simpan') - return; - } + const formData = new FormData(this); - for (const inputId in allFiles) { - allFiles[inputId].forEach((file, index) => { - formData.append(`data[${inputId}][file][]`, file); // gunakan inputId = name input file di HTML, misal "files[]" - }); - } - fetch(`/upload`, { + + fetch(`/uploadv2`, { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value, @@ -80,43 +47,29 @@ }).then(async(res) => { const responseData = await res.json(); if (responseData.status) { - const handler = function () { - Toastify({ - text: responseData.message || 'Berhasil melakukan aksi!', - duration: 3000, - gravity: "top", // bisa "bottom" - position: "right", // bisa "left" - style: { - background: "linear-gradient(to right, #00b09b, #96c93d)", // hijau gradasi - color: "#fff", - } - }).showToast(); - allFiles = []; - formCreate.find('input[type="file"].file-input').each(function () { - const newInput = $(this).clone(); // clone dengan attribute multiple - $(this).replaceWith(newInput); // ganti input lama dengan baru - bindFileUpload(newInput[0]) - // console.log(newInput); - - }); - colCount = 1; - $("#col_add_file").html('') - formCreate.find('select').val(null).trigger('change'); - document.querySelectorAll(".file-name").forEach(el => { - el.classList.add("d-none"); - el.innerHTML = ""; - }); - - if($("#klasifikasi_dok").val().length === 0 || $("#kategori_dok").val().length === 0 ){ - index() - }else{ - searchData() + Toastify({ + text: responseData.message || 'Berhasil melakukan aksi!', + duration: 3000, + gravity: "top", + position: "right", + style: { + background: "linear-gradient(to right, #00b09b, #96c93d)", + color: "#fff", } - submitBtn.prop('disabled', false).text('Simpan') - modalCreate.removeEventListener('hidden.bs.modal', handler); - }; - modalCreate.addEventListener('hidden.bs.modal', handler); - bootstrap.Modal.getInstance(modalCreate).hide(); + }).showToast(); + + resetCreateForm(); + + const kategoriVal = $("#kategori_dok").val() || []; + + if(kategoriVal.length === 0){ + index() + }else{ + searchData() + } + submitBtn.prop('disabled', false).text('Simpan') + const modalInstance = bootstrap.Modal.getInstance(modalCreate); + modalInstance?.hide(); } else { throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.'); } @@ -128,9 +81,7 @@ title: 'Gagal', text: err.message }); - submitBtn.prop('disabled', false).text('Simpan...') + submitBtn.prop('disabled', false).text('Simpan') } }); }); - - diff --git a/public/js/dashboard/functions.js b/public/js/dashboard/functions.js index 9c7153b..5c242b6 100644 --- a/public/js/dashboard/functions.js +++ b/public/js/dashboard/functions.js @@ -55,7 +55,6 @@ $(document).ready(function() { } }); - $('.klasifikasi_dok').select2(); $('.kategori_dok').select2(); if(allAkses){ @@ -91,54 +90,114 @@ function addForm(){ let html = ''; html += ` -
-
-
- -
-
- -
-
- - ${katDok.map(dok => ` `).join('')}
-
- - -
-
- -
- -
-
-
Format yang didukung: PDF, JPG, PNG, Excel dan Word
+ +
+ +
+ # + +
-
- +
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+ +
+ +
+ + +
+ +
+
+ +
+ Format yang didukung: PDF. +
+
+
` col.append(html) - let newInput = document.querySelector(`#fileUpload${colCount}`); + let newInput = document.querySelector(`#fileUpload_${colCount}`); bindFileUpload(newInput); if(allAkses){ selectOptionUnitKerjaV1(colCount) @@ -263,5 +322,3 @@ function selectOptionUnitKerjaV2(colCount) { }); } - - diff --git a/public/js/dashboard/index.js b/public/js/dashboard/index.js index 5ca4a28..1af6d30 100644 --- a/public/js/dashboard/index.js +++ b/public/js/dashboard/index.js @@ -40,20 +40,23 @@ function renderTree(units, katDok, keyword) {
{{-- @dd($allAkses) --}}
-
- -
- - -
+
+
+
+ + +
- -
- - -
+
+ + +
- -
- - -
+
+ + +
- -
- - -
+
+ + +
- -
- +
+ +
- - -
- +
+
+ Tips: pilih Unit/Sub Unit & Kategori untuk menampilkan data. +
+
+ Filter aktif siap digunakan +
-
- - +
+ + +
+
+ Umum + Internal +
@@ -141,6 +147,11 @@ const allAkses = @json($allAkses); const authUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->unitKerja); const authSubUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]); + function isPublic(permissionVal){ + if(permissionVal === null || permissionVal === undefined) return false; + const val = String(permissionVal).toLowerCase(); + return val === '1' || val === 'true' || val === 'iya' || val === 'yes'; + } let currentFile = null; let idDirectory = null; @@ -149,16 +160,22 @@ e.preventDefault(); let fileUrl = e.target.getAttribute('data-file'); - let fileName = e.target.getAttribute('data-name_file'); - let upload = e.target.getAttribute('data-upload'); - let time = e.target.getAttribute('data-time'); - let klasifikasiView = e.target.getAttribute('data-klasifikasi'); - console.log(fileUrl); + let fileName = e.target.getAttribute('data-fileName') || '-'; + let noDokumen = e.target.getAttribute('data-no_dokumen') || '-'; + let tanggalTerbit = e.target.getAttribute('data-tanggal_terbit') || '-'; + let klasifikasiView = e.target.getAttribute('data-klasifikasi') || '-'; + let permissionFile = e.target.getAttribute('data-permission_file'); - $("#confirm-upload-dokumen").html(upload); - $("#confirm-time-dokumen").html(time); - $("#confirm-upload-klasifikasi").html(klasifikasiView); - $("#confirm_preview_file").html(fileName); + $("#confirm-upload-dokumen").text(noDokumen); + $("#confirm-time-dokumen").text(tanggalTerbit); + $("#confirm-upload-klasifikasi").text(klasifikasiView); + $("#confirm_preview_file").text(fileName); + const permEl = document.getElementById('confirm-permission'); + if (permEl) { + const publicDoc = isPublic(permissionFile); + permEl.textContent = publicDoc ? 'Bisa dilihat unit lain' : 'Hanya unit ini'; + permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary'); + } currentFile = fileUrl; idDirectory = e.target.getAttribute('data-id'); @@ -203,7 +220,9 @@ }) .then(res => res.json()) .then(data => { - if (data.success) { + console.log(data); + + if (data.success) { Swal.fire({ text: 'File berhasil dihapus', icon: 'success', @@ -218,13 +237,6 @@ li?.remove(); } - // Reset modal preview - document.getElementById('file-preview').innerHTML = - `

📂 Pilih file untuk melihat preview

`; - document.getElementById('confirm_preview_file').innerHTML = ""; - document.getElementById('confirm-upload-dokumen').innerHTML = ""; - document.getElementById('confirm-time-dokumen').innerHTML = ""; - document.getElementById('confirm-upload-klasifikasi').innerHTML = ""; // Tutup modal otomatis setelah hapus let modalEl = document.getElementById('previewModal'); diff --git a/resources/views/dashboard/modal/create.blade.php b/resources/views/dashboard/modal/create.blade.php index 5fdfda7..502df94 100644 --- a/resources/views/dashboard/modal/create.blade.php +++ b/resources/views/dashboard/modal/create.blade.php @@ -9,54 +9,74 @@
-
+ @csrf
@@ -61,7 +61,7 @@ const mappingUnitKerjaPegawai = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]); const formCreate = $("#formFile") const modalCreate = document.getElementById('modalCreateFile') - const tableState = { data: [], filtered: [], page: 1, pageSize: 8, search: '' }; + const tableState = { data: [], page: 1, pageSize: 8, search: '', lastPage: 1, total: 0 }; const tbody = document.getElementById('tableFolderLastUpdated'); const paginationEl = document.getElementById('paginationControls'); const summaryEl = document.getElementById('tableSummary'); @@ -75,7 +75,7 @@ if(!isNaN(val) && val > 0){ tableState.pageSize = val; tableState.page = 1; - renderTable(); + fetchData(); } }); } @@ -159,29 +159,16 @@ if(!page) return; if(page === 'prev' && tableState.page > 1) tableState.page--; else if(page === 'next'){ - const totalPages = Math.max(1, Math.ceil(tableState.filtered.length / tableState.pageSize)); - if(tableState.page < totalPages) tableState.page++; + if(tableState.page < tableState.lastPage) tableState.page++; }else{ tableState.page = parseInt(page); } - renderTable(); + fetchData(); }); } function renderTable(){ - const term = tableState.search.toLowerCase(); - tableState.filtered = tableState.data.filter(item => { - const fileName = (item.file || '').split('/').pop().toLowerCase(); - const folderPath = (item.file || '').toLowerCase(); - return fileName.includes(term) || folderPath.includes(term); - }); - - const total = tableState.filtered.length; - const totalPages = Math.max(1, Math.ceil(total / tableState.pageSize)); - if(tableState.page > totalPages) tableState.page = totalPages; - - const startIdx = (tableState.page - 1) * tableState.pageSize; - const pageData = tableState.filtered.slice(startIdx, startIdx + tableState.pageSize); + const pageData = tableState.data || []; if(pageData.length === 0){ tbody.innerHTML = ` @@ -195,13 +182,13 @@ tbody.innerHTML = pageData.map(buildRow).join(''); } - const from = total === 0 ? 0 : startIdx + 1; - const to = Math.min(startIdx + pageData.length, total); + 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 = total ? `Menampilkan ${from} - ${to} dari ${total} dokumen` : 'Tidak ada data'; + summaryEl.textContent = tableState.total ? `Menampilkan ${from} - ${to} dari ${tableState.total} dokumen` : 'Tidak ada data'; } - renderPagination(totalPages); + renderPagination(tableState.lastPage || 1); } function debouncedTableSearch(value){ @@ -209,17 +196,23 @@ window.tableSearchTimer = setTimeout(() => { tableState.search = value.trim(); tableState.page = 1; - renderTable(); + fetchData(); }, 250); } function fetchData(){ if(summaryEl) summaryEl.textContent = 'Memuat data...'; - fetch(`/last-document`) + const params = new URLSearchParams({ + page: tableState.page, + per_page: tableState.pageSize, + keyword: tableState.search + }); + fetch(`/last-document?${params.toString()}`) .then(response => response.json()) .then(data => { tableState.data = data?.data || []; - tableState.page = 1; + tableState.lastPage = data?.pagination?.last_page || 1; + tableState.total = data?.pagination?.total || 0; renderTable(); }) .catch(error => { diff --git a/resources/views/layout/partials/sidenav.blade.php b/resources/views/layout/partials/sidenav.blade.php index cd442cb..410c098 100644 --- a/resources/views/layout/partials/sidenav.blade.php +++ b/resources/views/layout/partials/sidenav.blade.php @@ -63,9 +63,32 @@ Akses
+ + + + + diff --git a/resources/views/logActivity/index.blade.php b/resources/views/logActivity/index.blade.php new file mode 100644 index 0000000..553c776 --- /dev/null +++ b/resources/views/logActivity/index.blade.php @@ -0,0 +1,231 @@ +@extends('layout.main') +@section('body_main') +
+
+
+
+

Log Activity

+
+
+
+
+ + + + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + +
NamaUnitAktivitasNo DokumenTanggal
+
+
+
+ +
+
+
+ +@endsection + diff --git a/routes/web.php b/routes/web.php index e369817..25313d8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,6 +5,7 @@ use App\Http\Controllers\AuthController; use App\Http\Controllers\DashboardController; use App\Http\Controllers\MasterKategoriController; use App\Http\Controllers\MasterKlasifikasiController; +use App\Http\Controllers\LogActivityController; use Illuminate\Support\Facades\Route; Route::middleware(['auth'])->group(function(){ @@ -33,6 +34,12 @@ Route::middleware(['auth'])->group(function(){ Route::post('/download-multiple', [DashboardController::class, 'downloadDataMultiple']); Route::post('/download-byfolder', [DashboardController::class, 'downloadDataFolder']); + + Route::get('/log-activity', [LogActivityController::class, 'index']); + Route::get('/datatable/log-activity', [LogActivityController::class, 'datatable']); + + Route::get('/recap', [DashboardController::class, 'recapView']); + Route::get('/data/recap', [DashboardController::class, 'recapData']); }); Route::get('/login', [AuthController::class, 'index'])->name('login');