revisi done
@ -228,7 +228,7 @@ class DashboardController extends Controller
|
|||||||
'Unit',
|
'Unit',
|
||||||
'Sub Unit',
|
'Sub Unit',
|
||||||
'Tanggal Terbit',
|
'Tanggal Terbit',
|
||||||
'Tanggal Expired',
|
'Tanggal Kedaluwarsa Dokumen',
|
||||||
'Tanggal Upload',
|
'Tanggal Upload',
|
||||||
'Pengunggah'
|
'Pengunggah'
|
||||||
];
|
];
|
||||||
@ -370,8 +370,8 @@ class DashboardController extends Controller
|
|||||||
$katArray = $kategori ? explode(',', $kategori) : [];
|
$katArray = $kategori ? explode(',', $kategori) : [];
|
||||||
$katDok = MasterKategori::when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))->where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
|
$katDok = MasterKategori::when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))->where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
|
||||||
|
|
||||||
$applyFileFilters = function ($q) use ($keyword, $katArray, $subArray, $entryPegawaiId) {
|
$applyFileFilters = function ($q) use ($keyword, $katArray, $subArray) {
|
||||||
$q->where(function($subQuery) use ($entryPegawaiId){
|
$q->where(function($subQuery){
|
||||||
$subQuery->where('status_action', '!=', 'rejected')->whereNotNull('status_action');
|
$subQuery->where('status_action', '!=', 'rejected')->whereNotNull('status_action');
|
||||||
})
|
})
|
||||||
->when($subArray, fn($sq) => $sq->whereIn('id_sub_unit_kerja', $subArray))
|
->when($subArray, fn($sq) => $sq->whereIn('id_sub_unit_kerja', $subArray))
|
||||||
@ -598,41 +598,59 @@ class DashboardController extends Controller
|
|||||||
'message' => 'File tidak ditemukan'
|
'message' => 'File tidak ditemukan'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$oldPath= public_path('file/' . $data->file);
|
|
||||||
$fileInfo = pathinfo($data->file);
|
$fileInfo = pathinfo($data->file);
|
||||||
$newFileName = $fileInfo['filename'] . '_deleted.' . $fileInfo['extension'];
|
$newFileName = $fileInfo['filename'] . '_deleted.' . ($fileInfo['extension'] ?? '');
|
||||||
$newPath = public_path('file/' . $fileInfo['dirname'] . '/' . $newFileName);
|
$dirName = $fileInfo['dirname'] ?? '';
|
||||||
if (file_exists($oldPath)) {
|
$newPath = ($dirName && $dirName !== '.') ? ($dirName . '/' . $newFileName) : $newFileName;
|
||||||
// pastikan folder tujuan ada
|
$disk = Storage::disk('s3');
|
||||||
if (!is_dir(dirname($newPath))) {
|
if ($disk->exists($data->file)) {
|
||||||
mkdir(dirname($newPath), 0777, true);
|
// S3 tidak bisa rename langsung, jadi copy lalu delete
|
||||||
}
|
$disk->copy($data->file, $newPath);
|
||||||
rename($oldPath, $newPath);
|
$disk->delete($data->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data->update(['statusenabled' => false, 'file' => $fileInfo['dirname'].'/'. $newFileName]);
|
$data->update([
|
||||||
|
'statusenabled' => false,
|
||||||
|
'file' => $newPath
|
||||||
|
]);
|
||||||
|
|
||||||
$uploaderName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna';
|
$uploaderName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna';
|
||||||
$docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : $data->nama_dokumen;
|
$docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : $data->nama_dokumen;
|
||||||
$payloadNotification = [
|
$payloadNotification = [
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
'text_notifikasi' => "Dokumen {$docNumber} . dihapus oleh {$uploaderName}.",
|
'text_notifikasi' => "Dokumen {$docNumber} . dihapus oleh {$uploaderName}.",
|
||||||
'url' => '/pending-file',
|
'url' => '/pending-file',
|
||||||
'is_read' => false,
|
'is_read' => false,
|
||||||
'pegawai_id' => $mapping?->objectatasanlangsungfk,
|
'pegawai_id' => $mapping?->objectatasanlangsungfk,
|
||||||
];
|
];
|
||||||
|
|
||||||
Notifkasi::create($payloadNotification);
|
Notifkasi::create($payloadNotification);
|
||||||
if($mapping->objectpejabatpenilaifk){
|
if($mapping->objectpejabatpenilaifk){
|
||||||
$payloadNotification = [
|
$payloadNotification = [
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
'text_notifikasi' => "Dokumen {$docNumber}. dihapus oleh {$uploaderName}.",
|
'text_notifikasi' => "Dokumen {$docNumber}. dihapus oleh {$uploaderName}.",
|
||||||
'url' => '/pending-file',
|
'url' => '/pending-file',
|
||||||
'is_read' => false,
|
'is_read' => false,
|
||||||
'pegawai_id' => $mapping?->objectpejabatpenilaifk,
|
'pegawai_id' => $mapping?->objectpejabatpenilaifk,
|
||||||
];
|
];
|
||||||
Notifkasi::create($payloadNotification);
|
Notifkasi::create($payloadNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$payloadLog = [
|
||||||
|
'file_directory_id' => $data->file_directory_id,
|
||||||
|
'pegawai_id_entry' => $data->pegawai_id_entry,
|
||||||
|
'pegawai_nama_entry' => $data->pegawai_nama_entry,
|
||||||
|
'entry_at' => now(),
|
||||||
|
'file' => $data->file,
|
||||||
|
'statusenabled' => true,
|
||||||
|
'nama_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'no_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'mod_change' => null,
|
||||||
|
'id_unit_kerja' => $data ? $data->id_unit_kerja : null,
|
||||||
|
'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null,
|
||||||
|
'action_type' => 'Menghapus Dokumen',
|
||||||
|
];
|
||||||
|
LogActivity::create($payloadLog);
|
||||||
DB::connection('dbDirectory')->commit();
|
DB::connection('dbDirectory')->commit();
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
@ -644,7 +662,6 @@ class DashboardController extends Controller
|
|||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => 'Gagal menghapus data'
|
'message' => 'Gagal menghapus data'
|
||||||
]);
|
]);
|
||||||
//throw $th;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -742,20 +759,35 @@ class DashboardController extends Controller
|
|||||||
$zipPath = public_path('zip/' . $zipName);
|
$zipPath = public_path('zip/' . $zipName);
|
||||||
$zip = new ZipArchive;
|
$zip = new ZipArchive;
|
||||||
$tempFiles = [];
|
$tempFiles = [];
|
||||||
|
$tempDownloads = [];
|
||||||
|
$disk = Storage::disk('s3');
|
||||||
|
$tempDir = storage_path('app/temp');
|
||||||
|
if (!is_dir($tempDir)) {
|
||||||
|
@mkdir($tempDir, 0777, true);
|
||||||
|
}
|
||||||
|
if (!is_dir(public_path('zip'))) {
|
||||||
|
@mkdir(public_path('zip'), 0777, true);
|
||||||
|
}
|
||||||
if($zip->open($zipPath, ZipArchive::CREATE) === TRUE){
|
if($zip->open($zipPath, ZipArchive::CREATE) === TRUE){
|
||||||
foreach ($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
$fullPath = public_path('file/' . $path);
|
if(!$disk->exists($path)){
|
||||||
if(!file_exists($fullPath)){
|
|
||||||
throw new \Exception("File tidak ditemukan: " . $path);
|
throw new \Exception("File tidak ditemukan: " . $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
$relativePathInZip = $path;
|
$relativePathInZip = $path;
|
||||||
$fileToAdd = $this->prepareFileWithWatermark($fullPath, $tempFiles);
|
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
||||||
|
$ext = $ext ? strtolower($ext) : 'bin';
|
||||||
|
$localPath = $tempDir . '/' . uniqid('s3_') . '.' . $ext;
|
||||||
|
file_put_contents($localPath, $disk->get($path));
|
||||||
|
$tempDownloads[] = $localPath;
|
||||||
|
|
||||||
|
$fileToAdd = $this->prepareFileWithWatermark($localPath, $tempFiles);
|
||||||
$zip->addFile($fileToAdd, $relativePathInZip);
|
$zip->addFile($fileToAdd, $relativePathInZip);
|
||||||
}
|
}
|
||||||
$zip->close();
|
$zip->close();
|
||||||
}
|
}
|
||||||
$this->cleanupTempFiles($tempFiles);
|
$this->cleanupTempFiles($tempFiles);
|
||||||
|
$this->cleanupTempFiles($tempDownloads);
|
||||||
return response()->download(public_path('zip/' . $zipName))->deleteFileAfterSend(true);
|
return response()->download(public_path('zip/' . $zipName))->deleteFileAfterSend(true);
|
||||||
//code...
|
//code...
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
@ -814,9 +846,8 @@ class DashboardController extends Controller
|
|||||||
if (!$data) {
|
if (!$data) {
|
||||||
abort(404, 'File tidak ditemukan');
|
abort(404, 'File tidak ditemukan');
|
||||||
}
|
}
|
||||||
|
$disk = Storage::disk('s3');
|
||||||
$filePath = public_path('file/' . $data->file);
|
if (!$data->file || !$disk->exists($data->file)) {
|
||||||
if (!file_exists($filePath)) {
|
|
||||||
abort(404, 'File tidak ditemukan');
|
abort(404, 'File tidak ditemukan');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,16 +869,34 @@ class DashboardController extends Controller
|
|||||||
'id_sub_unit_kerja' => $mapping ? $mapping->objectsubunitkerjapegawaifk : null,
|
'id_sub_unit_kerja' => $mapping ? $mapping->objectsubunitkerjapegawaifk : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$tempDir = storage_path('app/temp');
|
||||||
|
if (!is_dir($tempDir)) {
|
||||||
|
@mkdir($tempDir, 0777, true);
|
||||||
|
}
|
||||||
|
$ext = pathinfo((string) $data->file, PATHINFO_EXTENSION);
|
||||||
|
$ext = $ext ? strtolower($ext) : 'bin';
|
||||||
|
$localPath = $tempDir . '/' . uniqid('s3_') . '.' . $ext;
|
||||||
|
file_put_contents($localPath, $disk->get($data->file));
|
||||||
|
|
||||||
$tempFiles = [];
|
$tempFiles = [];
|
||||||
$fileToSend = $this->prepareFileWithWatermark($filePath, $tempFiles);
|
$fileToSend = $this->prepareFileWithWatermark($localPath, $tempFiles);
|
||||||
$downloadName = basename($data->file);
|
$downloadName = basename($data->file);
|
||||||
|
|
||||||
$response = response()->download($fileToSend, $downloadName);
|
$response = response()->download($fileToSend, $downloadName);
|
||||||
if ($fileToSend !== $filePath) {
|
$response->deleteFileAfterSend(true);
|
||||||
$response->deleteFileAfterSend(true);
|
$cleanup = array_merge($tempFiles, [$localPath]);
|
||||||
} else {
|
$cleanup = array_values(array_unique(array_filter($cleanup)));
|
||||||
$this->cleanupTempFiles($tempFiles);
|
// cleanup after response is sent
|
||||||
}
|
register_shutdown_function(function () use ($cleanup, $fileToSend) {
|
||||||
|
foreach ($cleanup as $file) {
|
||||||
|
if ($file === $fileToSend) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_string($file) && $file !== '' && file_exists($file)) {
|
||||||
|
@unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
@ -870,9 +919,7 @@ class DashboardController extends Controller
|
|||||||
|
|
||||||
public function datatableDataUmum(){
|
public function datatableDataUmum(){
|
||||||
$perPage = (int) request('per_page', 10);
|
$perPage = (int) request('per_page', 10);
|
||||||
// $authUnitId = auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->objectunitkerjapegawaifk;
|
|
||||||
$user = auth()->user()?->dataUser;
|
$user = auth()->user()?->dataUser;
|
||||||
// $entryPegawaiId = auth()->user()?->objectpegawaifk;
|
|
||||||
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
|
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
|
||||||
$keyword = request('keyword');
|
$keyword = request('keyword');
|
||||||
$unitId = request('unit');
|
$unitId = request('unit');
|
||||||
@ -883,21 +930,6 @@ class DashboardController extends Controller
|
|||||||
$kategoriIds = is_array($kategori)
|
$kategoriIds = is_array($kategori)
|
||||||
? array_values(array_filter($kategori))
|
? array_values(array_filter($kategori))
|
||||||
: array_values(array_filter(explode(',', (string) $kategori)));
|
: array_values(array_filter(explode(',', (string) $kategori)));
|
||||||
$mapping = MappingUnitKerjaPegawai::where('statusenabled', true)
|
|
||||||
->where('objectpegawaifk', $user->id)
|
|
||||||
->get(['objectunitkerjapegawaifk', 'objectsubunitkerjapegawaifk']);
|
|
||||||
|
|
||||||
// $unitIds = $mapping->pluck('objectunitkerjapegawaifk')
|
|
||||||
// ->filter() // buang null
|
|
||||||
// ->unique()
|
|
||||||
// ->values()
|
|
||||||
// ->all();
|
|
||||||
|
|
||||||
// $subUnitIds = $mapping->pluck('objectsubunitkerjapegawaifk')
|
|
||||||
// ->filter()
|
|
||||||
// ->unique()
|
|
||||||
// ->values()
|
|
||||||
// ->all();
|
|
||||||
$query = FileDirectory::where('statusenabled', true)->where('status_action', 'approved')
|
$query = FileDirectory::where('statusenabled', true)->where('status_action', 'approved')
|
||||||
->when(!empty($unitIds), function ($q) use ($unitIds) {
|
->when(!empty($unitIds), function ($q) use ($unitIds) {
|
||||||
$q->whereIn('id_unit_kerja', $unitIds);
|
$q->whereIn('id_unit_kerja', $unitIds);
|
||||||
@ -959,7 +991,7 @@ class DashboardController extends Controller
|
|||||||
'Unit',
|
'Unit',
|
||||||
'Sub Unit',
|
'Sub Unit',
|
||||||
'Tanggal Terbit',
|
'Tanggal Terbit',
|
||||||
'Tanggal Expired',
|
'Tanggal Kedaluwarsa Dokumen',
|
||||||
'Tanggal Upload',
|
'Tanggal Upload',
|
||||||
];
|
];
|
||||||
$sheet->fromArray($headers, null, 'A4');
|
$sheet->fromArray($headers, null, 'A4');
|
||||||
@ -1058,10 +1090,17 @@ class DashboardController extends Controller
|
|||||||
$imageName = $ext ? (Str::uuid()->toString() . '.' . $ext) : Str::uuid()->toString();
|
$imageName = $ext ? (Str::uuid()->toString() . '.' . $ext) : Str::uuid()->toString();
|
||||||
}
|
}
|
||||||
$path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}";
|
$path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}";
|
||||||
$disk = Storage::disk('file_directory');
|
$disk = Storage::disk('s3');
|
||||||
$disk->makeDirectory($path);
|
|
||||||
$disk->putFileAs($path, $uploadedFile, $imageName);
|
$disk->putFileAs(
|
||||||
$payload['file'] =$path .'/' .$imageName;
|
$path,
|
||||||
|
$uploadedFile,
|
||||||
|
$imageName,
|
||||||
|
['visibility' => 'private'] // atau 'public'
|
||||||
|
);
|
||||||
|
|
||||||
|
$payload['file'] = $path . '/' . $imageName;
|
||||||
|
|
||||||
|
|
||||||
$fd = FileDirectory::create($payload);
|
$fd = FileDirectory::create($payload);
|
||||||
|
|
||||||
@ -1114,6 +1153,9 @@ class DashboardController extends Controller
|
|||||||
public function dataPdf($fileDirectoryId)
|
public function dataPdf($fileDirectoryId)
|
||||||
{
|
{
|
||||||
$data = FileDirectory::where('file_directory_id', $fileDirectoryId)->first();
|
$data = FileDirectory::where('file_directory_id', $fileDirectoryId)->first();
|
||||||
|
if (!$data) {
|
||||||
|
abort(404, 'PDF Tidak ditemukan');
|
||||||
|
}
|
||||||
$user = auth()->user()->dataUser;
|
$user = auth()->user()->dataUser;
|
||||||
$mapping = MappingUnitKerjaPegawai::where('statusenabled', true)
|
$mapping = MappingUnitKerjaPegawai::where('statusenabled', true)
|
||||||
->where('objectpegawaifk', $user->id)->where('isprimary', true)
|
->where('objectpegawaifk', $user->id)->where('isprimary', true)
|
||||||
@ -1134,38 +1176,48 @@ class DashboardController extends Controller
|
|||||||
LogActivity::create($payloadLog);
|
LogActivity::create($payloadLog);
|
||||||
|
|
||||||
|
|
||||||
$filePath = public_path('file/' . $data->file);
|
$fileInfo = get_file_s3($data->file);
|
||||||
|
if (!$fileInfo || empty($fileInfo['file'])) {
|
||||||
if (!file_exists($filePath)) {
|
|
||||||
abort(404, 'PDF Tidak ditemukan');
|
abort(404, 'PDF Tidak ditemukan');
|
||||||
}
|
}
|
||||||
|
$mime = $fileInfo['mime'] ?? 'application/pdf';
|
||||||
|
$tempDir = storage_path('app/temp');
|
||||||
|
if (!is_dir($tempDir)) {
|
||||||
|
@mkdir($tempDir, 0777, true);
|
||||||
|
}
|
||||||
|
$ext = pathinfo((string) $data->file, PATHINFO_EXTENSION);
|
||||||
|
$ext = $ext ? strtolower($ext) : 'pdf';
|
||||||
|
$localPath = $tempDir . '/' . uniqid('s3_') . '.' . $ext;
|
||||||
|
file_put_contents($localPath, $fileInfo['file']);
|
||||||
|
|
||||||
$stampFile = public_path('assets/copy.png');
|
$stampFile = public_path('assets/copy.png');
|
||||||
if (!file_exists($stampFile)) {
|
$tempConverted = $tempDir . '/' . uniqid('conv_') . '.pdf';
|
||||||
// kalau watermark tidak ada, tampilkan file asli
|
$resp = null;
|
||||||
return response()->file($filePath, [
|
|
||||||
'Content-Type' => 'application/pdf',
|
|
||||||
'Content-Disposition' => 'inline; filename="preview.pdf"',
|
|
||||||
'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tempConverted = storage_path('app/temp/' . uniqid('conv_') . '.pdf');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// coba watermark langsung
|
if (!file_exists($stampFile)) {
|
||||||
return $this->watermarkCenterAndStream($filePath, $stampFile);
|
// kalau watermark tidak ada, tampilkan file asli
|
||||||
|
$resp = response($fileInfo['file'], 200, [
|
||||||
} catch (\Throwable $e) {
|
'Content-Type' => $mime,
|
||||||
// kalau gagal (PDF modern) -> convert dulu
|
'Content-Disposition' => 'inline; filename="preview.pdf"',
|
||||||
// dd($e);
|
'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
|
||||||
$this->convertWithGhostscript($filePath, $tempConverted);
|
]);
|
||||||
|
} else {
|
||||||
$resp = $this->watermarkCenterAndStream($tempConverted, $stampFile);
|
try {
|
||||||
|
// coba watermark langsung
|
||||||
@unlink($tempConverted);
|
$resp = $this->watermarkCenterAndStream($localPath, $stampFile);
|
||||||
return $resp;
|
} catch (\Throwable $e) {
|
||||||
|
// kalau gagal (PDF modern) -> convert dulu
|
||||||
|
$this->convertWithGhostscript($localPath, $tempConverted);
|
||||||
|
$resp = $this->watermarkCenterAndStream($tempConverted, $stampFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
@unlink($localPath);
|
||||||
|
if (file_exists($tempConverted)) {
|
||||||
|
@unlink($tempConverted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return $resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function watermarkCenterAndStream(string $pdfPath, string $stampFile)
|
private function watermarkCenterAndStream(string $pdfPath, string $stampFile)
|
||||||
@ -1433,7 +1485,7 @@ class DashboardController extends Controller
|
|||||||
return [
|
return [
|
||||||
'file_directory_id' => $item->file_directory_id,
|
'file_directory_id' => $item->file_directory_id,
|
||||||
'pegawai_nama_entry' => $item->pegawai_nama_entry,
|
'pegawai_nama_entry' => $item->pegawai_nama_entry,
|
||||||
'part' => $dataSlice[0] . '/' . $dataSlice[1],
|
'part' => $dataSlice[0],
|
||||||
'folder' => $dataSlice[2],
|
'folder' => $dataSlice[2],
|
||||||
'fileName' =>$dataSlice[3],
|
'fileName' =>$dataSlice[3],
|
||||||
'file' => $item->file,
|
'file' => $item->file,
|
||||||
@ -1490,6 +1542,22 @@ class DashboardController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
Notifkasi::create($payloadNotification);
|
Notifkasi::create($payloadNotification);
|
||||||
|
|
||||||
|
$payloadLog = [
|
||||||
|
'file_directory_id' => $data->file_directory_id,
|
||||||
|
'pegawai_id_entry' => $data->pegawai_id_entry,
|
||||||
|
'pegawai_nama_entry' => $data->pegawai_nama_entry,
|
||||||
|
'entry_at' => now(),
|
||||||
|
'file' => $data->file,
|
||||||
|
'statusenabled' => true,
|
||||||
|
'nama_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'no_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'mod_change' => null,
|
||||||
|
'id_unit_kerja' => $data ? $data->id_unit_kerja : null,
|
||||||
|
'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null,
|
||||||
|
'action_type' => 'Approved Dokumen',
|
||||||
|
];
|
||||||
|
LogActivity::create($payloadLog);
|
||||||
DB::connection('dbDirectory')->commit();
|
DB::connection('dbDirectory')->commit();
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => true,
|
'status' => true,
|
||||||
@ -1609,6 +1677,21 @@ class DashboardController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
Notifkasi::create($payloadNotification);
|
Notifkasi::create($payloadNotification);
|
||||||
|
$payloadLog = [
|
||||||
|
'file_directory_id' => $data->file_directory_id,
|
||||||
|
'pegawai_id_entry' => $data->pegawai_id_entry,
|
||||||
|
'pegawai_nama_entry' => $data->pegawai_nama_entry,
|
||||||
|
'entry_at' => now(),
|
||||||
|
'file' => $data->file,
|
||||||
|
'statusenabled' => true,
|
||||||
|
'nama_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'no_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'mod_change' => null,
|
||||||
|
'id_unit_kerja' => $data ? $data->id_unit_kerja : null,
|
||||||
|
'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null,
|
||||||
|
'action_type' => 'Rejected Dokumen',
|
||||||
|
];
|
||||||
|
LogActivity::create($payloadLog);
|
||||||
DB::connection('dbDirectory')->commit();
|
DB::connection('dbDirectory')->commit();
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => true,
|
'status' => true,
|
||||||
@ -1752,11 +1835,18 @@ class DashboardController extends Controller
|
|||||||
$keyword = request('keyword');
|
$keyword = request('keyword');
|
||||||
$start = request('start_date');
|
$start = request('start_date');
|
||||||
$end = request('end_date');
|
$end = request('end_date');
|
||||||
$query = FileDirectory::where('statusenabled', true)->where('pegawai_id_entry', auth()->user()->objectpegawaifk)
|
$isHistory = filter_var(request('history'), FILTER_VALIDATE_BOOLEAN);
|
||||||
->where(function($q){
|
$query = FileDirectory::where('statusenabled', true)
|
||||||
$q->where('status_action', '!=', 'approved')
|
->where('pegawai_id_entry', auth()->user()->objectpegawaifk)
|
||||||
->orWhereNull('status_action');
|
->when($isHistory, function($q){
|
||||||
})->orderBy('entry_at','desc');
|
$q->where('status_action', 'approved');
|
||||||
|
}, function($q){
|
||||||
|
$q->where(function($sub){
|
||||||
|
$sub->where('status_action', '!=', 'approved')
|
||||||
|
->orWhereNull('status_action');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->orderBy('entry_at','desc');
|
||||||
if($keyword){
|
if($keyword){
|
||||||
$query->where(function($q) use ($keyword){
|
$query->where(function($q) use ($keyword){
|
||||||
$q->where('file', 'ILIKE', "%{$keyword}%")
|
$q->where('file', 'ILIKE', "%{$keyword}%")
|
||||||
@ -1896,8 +1986,18 @@ class DashboardController extends Controller
|
|||||||
}
|
}
|
||||||
$imageName = $uploadedFile->getClientOriginalName();
|
$imageName = $uploadedFile->getClientOriginalName();
|
||||||
$path = $folderPath ? "{$folderPath}" : '';
|
$path = $folderPath ? "{$folderPath}" : '';
|
||||||
$uploadedFile->storeAs($path, $imageName, 'file_directory');
|
$disk = Storage::disk('s3');
|
||||||
|
$oldFile = $data->file;
|
||||||
|
$disk->putFileAs(
|
||||||
|
$path,
|
||||||
|
$uploadedFile,
|
||||||
|
$imageName,
|
||||||
|
['visibility' => 'private']
|
||||||
|
);
|
||||||
$payload['file'] = ($path ? $path . '/' : '') . $imageName;
|
$payload['file'] = ($path ? $path . '/' : '') . $imageName;
|
||||||
|
if ($oldFile && $oldFile !== $payload['file'] && $disk->exists($oldFile)) {
|
||||||
|
$disk->delete($oldFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$payload['status_action'] = 'revised';
|
$payload['status_action'] = 'revised';
|
||||||
|
|
||||||
@ -1932,7 +2032,23 @@ class DashboardController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
Notifkasi::create($payloadNotification);
|
Notifkasi::create($payloadNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$payloadLog = [
|
||||||
|
'file_directory_id' => $data->file_directory_id,
|
||||||
|
'pegawai_id_entry' => $data->pegawai_nama_entry,
|
||||||
|
'pegawai_nama_entry' => $data->pegawai_nama_entry,
|
||||||
|
'entry_at' => now(),
|
||||||
|
'file' => $data->file,
|
||||||
|
'statusenabled' => true,
|
||||||
|
'nama_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'no_dokumen' => $data->nama_dokumen ?? null,
|
||||||
|
'mod_change' => null,
|
||||||
|
'id_unit_kerja' => $data ? $data->id_unit_kerja : null,
|
||||||
|
'id_sub_unit_kerja' => $data ? $data->id_sub_unit_kerja : null,
|
||||||
|
'action_type' => 'Revisi Dokumen',
|
||||||
|
];
|
||||||
|
LogActivity::create($payloadLog);
|
||||||
|
|
||||||
DB::connection('dbDirectory')->commit();
|
DB::connection('dbDirectory')->commit();
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -1947,4 +2063,109 @@ class DashboardController extends Controller
|
|||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public function historyPengajuan(){
|
||||||
|
// $data = FileDirectory::where('statusenabled', true)->where('pegawai_id_entry', auth()->user()->objectpegawaifk)->get();
|
||||||
|
// return $data;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function logDokumen()
|
||||||
|
{
|
||||||
|
$perPage = (int) request('per_page', 10);
|
||||||
|
$keyword = request('keyword');
|
||||||
|
$start = request('start_date');
|
||||||
|
$end = request('end_date');
|
||||||
|
|
||||||
|
$queryIsAtasan = MappingUnitKerjaPegawai::where('statusenabled', true)
|
||||||
|
->where(function ($q) {
|
||||||
|
$q->where('objectatasanlangsungfk', auth()->user()?->dataUser?->id)
|
||||||
|
->orWhere('objectpejabatpenilaifk', auth()->user()->objectpegawaifk);
|
||||||
|
});
|
||||||
|
$isAtasan = $queryIsAtasan->exists();
|
||||||
|
|
||||||
|
$query = LogActivity::query()
|
||||||
|
->from('logging.log_activity_file_directory as log')
|
||||||
|
->leftJoin('public.file_directory as fd', 'fd.file_directory_id', '=', 'log.file_directory_id')
|
||||||
|
->where('log.statusenabled', true)
|
||||||
|
->whereNotIn('log.action_type', ['Membuka Dokumen', 'Download Dokumen'])
|
||||||
|
->select([
|
||||||
|
'log.file_directory_id',
|
||||||
|
'log.pegawai_nama_entry',
|
||||||
|
'log.file',
|
||||||
|
'log.no_dokumen',
|
||||||
|
'log.nama_dokumen',
|
||||||
|
'log.entry_at',
|
||||||
|
'log.action_type',
|
||||||
|
'log.id_unit_kerja',
|
||||||
|
'log.id_sub_unit_kerja',
|
||||||
|
'fd.permission_file',
|
||||||
|
'fd.tanggal_terbit',
|
||||||
|
'fd.tgl_expired',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($isAtasan) {
|
||||||
|
$unitIds = $queryIsAtasan
|
||||||
|
->get(['objectunitkerjapegawaifk'])
|
||||||
|
->pluck('objectunitkerjapegawaifk')
|
||||||
|
->filter()
|
||||||
|
->unique()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
if (!empty($unitIds)) {
|
||||||
|
$query->whereIn('log.id_unit_kerja', $unitIds);
|
||||||
|
} else {
|
||||||
|
$query->whereRaw('1 = 0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$query->where('log.pegawai_id_entry', auth()->user()->objectpegawaifk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($keyword) {
|
||||||
|
$query->where(function ($q) use ($keyword) {
|
||||||
|
$q->where('log.file', 'ILIKE', "%{$keyword}%")
|
||||||
|
->orWhere('log.no_dokumen', 'ILIKE', "%{$keyword}%")
|
||||||
|
->orWhere('log.nama_dokumen', 'ILIKE', "%{$keyword}%")
|
||||||
|
->orWhere('log.action_type', 'ILIKE', "%{$keyword}%");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ($start) {
|
||||||
|
$query->whereDate('log.entry_at', '>=', $start);
|
||||||
|
}
|
||||||
|
if ($end) {
|
||||||
|
$query->whereDate('log.entry_at', '<=', $end);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginated = $query->orderBy('log.entry_at', 'desc')->paginate($perPage);
|
||||||
|
$data = $paginated->getCollection()->map(function ($item) {
|
||||||
|
$parts = array_values(array_filter(explode('/', (string) $item->file)));
|
||||||
|
return [
|
||||||
|
'file_directory_id' => $item->file_directory_id,
|
||||||
|
'pegawai_nama_entry' => $item->pegawai_nama_entry,
|
||||||
|
'part' => $parts[0] ?? '-',
|
||||||
|
'folder' => $parts[2] ?? '-',
|
||||||
|
'fileName' => $parts[3] ?? '-',
|
||||||
|
'file' => $item->file,
|
||||||
|
'no_dokumen' => $item->no_dokumen,
|
||||||
|
'nama_dokumen' => $item->nama_dokumen,
|
||||||
|
'entry_at' => $item->entry_at,
|
||||||
|
'tanggal_terbit' => $item->tanggal_terbit,
|
||||||
|
'tgl_expired' => $item->tgl_expired,
|
||||||
|
'permission_file' => $item->permission_file,
|
||||||
|
'action_type' => $item->action_type,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
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(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,4 +120,6 @@ class LogActivityController extends Controller
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
if(!function_exists('ver')){
|
if(!function_exists('ver')){
|
||||||
function ver($path){
|
function ver($path){
|
||||||
$fullPath = public_path($path);
|
$fullPath = public_path($path);
|
||||||
return asset($path) . '?v=' . (file_exists($fullPath) ? filemtime($fullPath) : time());
|
return asset($path) . '?v=' . (file_exists($fullPath) ? filemtime($fullPath) : time());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('get_file_s3')) {
|
||||||
|
function get_file_s3($path)
|
||||||
|
{
|
||||||
|
if (!Storage::disk('s3')->exists($path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = Storage::disk('s3')->get($path);
|
||||||
|
$mime = Storage::disk('s3')->mimeType($path);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'file' => $file,
|
||||||
|
'mime' => $mime
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/tinker": "^2.10.1",
|
"laravel/tinker": "^2.10.1",
|
||||||
|
"league/flysystem-aws-s3-v3": "3.0",
|
||||||
"phpoffice/phpspreadsheet": "^5.4",
|
"phpoffice/phpspreadsheet": "^5.4",
|
||||||
"setasign/fpdf": "^1.8",
|
"setasign/fpdf": "^1.8",
|
||||||
"setasign/fpdi": "^2.6"
|
"setasign/fpdi": "^2.6"
|
||||||
|
|||||||
345
composer.lock
generated
@ -4,8 +4,159 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "08bd514ba1ce7ebc80cd60f3bb76e101",
|
"content-hash": "127440b3f9ffff6fa5a355be4bb0a3fb",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "aws/aws-crt-php",
|
||||||
|
"version": "v1.2.7",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/awslabs/aws-crt-php.git",
|
||||||
|
"reference": "d71d9906c7bb63a28295447ba12e74723bd3730e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e",
|
||||||
|
"reference": "d71d9906c7bb63a28295447ba12e74723bd3730e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
|
||||||
|
"yoast/phpunit-polyfills": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "AWS SDK Common Runtime Team",
|
||||||
|
"email": "aws-sdk-common-runtime@amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS Common Runtime for PHP",
|
||||||
|
"homepage": "https://github.com/awslabs/aws-crt-php",
|
||||||
|
"keywords": [
|
||||||
|
"amazon",
|
||||||
|
"aws",
|
||||||
|
"crt",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/awslabs/aws-crt-php/issues",
|
||||||
|
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7"
|
||||||
|
},
|
||||||
|
"time": "2024-10-18T22:15:13+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aws/aws-sdk-php",
|
||||||
|
"version": "3.369.26",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
|
"reference": "ad0916c6595d98f9052f60e1d7204f4740369e94"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ad0916c6595d98f9052f60e1d7204f4740369e94",
|
||||||
|
"reference": "ad0916c6595d98f9052f60e1d7204f4740369e94",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"aws/aws-crt-php": "^1.2.3",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"guzzlehttp/guzzle": "^7.4.5",
|
||||||
|
"guzzlehttp/promises": "^2.0",
|
||||||
|
"guzzlehttp/psr7": "^2.4.5",
|
||||||
|
"mtdowling/jmespath.php": "^2.8.0",
|
||||||
|
"php": ">=8.1",
|
||||||
|
"psr/http-message": "^1.0 || ^2.0",
|
||||||
|
"symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"andrewsville/php-token-reflection": "^1.4",
|
||||||
|
"aws/aws-php-sns-message-validator": "~1.0",
|
||||||
|
"behat/behat": "~3.0",
|
||||||
|
"composer/composer": "^2.7.8",
|
||||||
|
"dms/phpunit-arraysubset-asserts": "^0.4.0",
|
||||||
|
"doctrine/cache": "~1.4",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"phpunit/phpunit": "^9.6",
|
||||||
|
"psr/cache": "^2.0 || ^3.0",
|
||||||
|
"psr/simple-cache": "^2.0 || ^3.0",
|
||||||
|
"sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0",
|
||||||
|
"yoast/phpunit-polyfills": "^2.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
|
||||||
|
"doctrine/cache": "To use the DoctrineCacheAdapter",
|
||||||
|
"ext-curl": "To send requests using cURL",
|
||||||
|
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
|
||||||
|
"ext-pcntl": "To use client-side monitoring",
|
||||||
|
"ext-sockets": "To use client-side monitoring"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Aws\\": "src/"
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"src/data/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Amazon Web Services",
|
||||||
|
"homepage": "http://aws.amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
|
||||||
|
"homepage": "http://aws.amazon.com/sdkforphp",
|
||||||
|
"keywords": [
|
||||||
|
"amazon",
|
||||||
|
"aws",
|
||||||
|
"cloud",
|
||||||
|
"dynamodb",
|
||||||
|
"ec2",
|
||||||
|
"glacier",
|
||||||
|
"s3",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||||
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.369.26"
|
||||||
|
},
|
||||||
|
"time": "2026-02-03T19:16:42+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
"version": "0.13.1",
|
"version": "0.13.1",
|
||||||
@ -1807,6 +1958,62 @@
|
|||||||
},
|
},
|
||||||
"time": "2025-06-25T13:29:59+00:00"
|
"time": "2025-06-25T13:29:59+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "league/flysystem-aws-s3-v3",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
|
||||||
|
"reference": "f8ba6a92a5c1fdcbdd89dede009a1e6e1b93ba8c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/f8ba6a92a5c1fdcbdd89dede009a1e6e1b93ba8c",
|
||||||
|
"reference": "f8ba6a92a5c1fdcbdd89dede009a1e6e1b93ba8c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"aws/aws-sdk-php": "^3.132.4",
|
||||||
|
"league/flysystem": "^2.0.0 || ^3.0.0",
|
||||||
|
"league/mime-type-detection": "^1.0.0",
|
||||||
|
"php": "^8.0.2"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"guzzlehttp/guzzle": "<7.0",
|
||||||
|
"guzzlehttp/ringphp": "<1.1.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Flysystem\\AwsS3V3\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "info@frankdejonge.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS S3 filesystem adapter for Flysystem.",
|
||||||
|
"keywords": [
|
||||||
|
"Flysystem",
|
||||||
|
"aws",
|
||||||
|
"file",
|
||||||
|
"files",
|
||||||
|
"filesystem",
|
||||||
|
"s3",
|
||||||
|
"storage"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues",
|
||||||
|
"source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.0.0"
|
||||||
|
},
|
||||||
|
"time": "2022-01-13T21:11:49+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "league/flysystem-local",
|
"name": "league/flysystem-local",
|
||||||
"version": "3.30.0",
|
"version": "3.30.0",
|
||||||
@ -2374,6 +2581,72 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-03-24T10:02:05+00:00"
|
"time": "2025-03-24T10:02:05+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "mtdowling/jmespath.php",
|
||||||
|
"version": "2.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jmespath/jmespath.php.git",
|
||||||
|
"reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
|
||||||
|
"reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"symfony/polyfill-mbstring": "^1.17"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/xdebug-handler": "^3.0.3",
|
||||||
|
"phpunit/phpunit": "^8.5.33"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/jp.php"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.8-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/JmesPath.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"JmesPath\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Declaratively specify how to extract elements from a JSON document",
|
||||||
|
"keywords": [
|
||||||
|
"json",
|
||||||
|
"jsonpath"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/jmespath/jmespath.php/issues",
|
||||||
|
"source": "https://github.com/jmespath/jmespath.php/tree/2.8.0"
|
||||||
|
},
|
||||||
|
"time": "2024-09-04T18:46:31+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "nesbot/carbon",
|
"name": "nesbot/carbon",
|
||||||
"version": "3.10.2",
|
"version": "3.10.2",
|
||||||
@ -4310,6 +4583,76 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-09-25T14:21:43+00:00"
|
"time": "2024-09-25T14:21:43+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/filesystem",
|
||||||
|
"version": "v7.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/filesystem.git",
|
||||||
|
"reference": "d551b38811096d0be9c4691d406991b47c0c630a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a",
|
||||||
|
"reference": "d551b38811096d0be9c4691d406991b47c0c630a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"symfony/polyfill-ctype": "~1.8",
|
||||||
|
"symfony/polyfill-mbstring": "~1.8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/process": "^6.4|^7.0|^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Filesystem\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides basic utilities for the filesystem",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/filesystem/tree/v7.4.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-11-27T13:27:24+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/finder",
|
"name": "symfony/finder",
|
||||||
"version": "v7.3.2",
|
"version": "v7.3.2",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 466 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 168 KiB |
@ -1,7 +1,11 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '' };
|
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '', mode: 'pengajuan' };
|
||||||
const tbody = document.getElementById('tablePendingFile');
|
const historyState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '', mode: 'history' };
|
||||||
const paginationEl = document.getElementById('paginationControls');
|
|
||||||
|
const tbodyPending = document.getElementById('tablePendingFile');
|
||||||
|
const tbodyHistory = document.getElementById('tableHistoryFile');
|
||||||
|
const paginationPendingEl = document.getElementById('paginationControls');
|
||||||
|
const paginationHistoryEl = document.getElementById('paginationHistory');
|
||||||
const summaryEl = document.getElementById('tableSummary');
|
const summaryEl = document.getElementById('tableSummary');
|
||||||
const pageSizeSelect = document.getElementById('tablePageSize');
|
const pageSizeSelect = document.getElementById('tablePageSize');
|
||||||
const startDateInput = document.getElementById('startDate');
|
const startDateInput = document.getElementById('startDate');
|
||||||
@ -10,26 +14,42 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const bulkApproveBtn = document.getElementById('bulkApproveBtn');
|
const bulkApproveBtn = document.getElementById('bulkApproveBtn');
|
||||||
const clearSelectionBtn = document.getElementById('clearSelectionBtn');
|
const clearSelectionBtn = document.getElementById('clearSelectionBtn');
|
||||||
const selectedCountEl = document.getElementById('selectedCount');
|
const selectedCountEl = document.getElementById('selectedCount');
|
||||||
|
const pendingBulkActionsEl = document.getElementById('pendingBulkActions');
|
||||||
|
const tabsEl = document.getElementById('pengajuanTabs');
|
||||||
|
const titleEl = document.getElementById('pendingTitle');
|
||||||
|
const tabPendingEl = document.getElementById('tabPengajuan');
|
||||||
|
const tabHistoryEl = document.getElementById('tabHistory');
|
||||||
|
|
||||||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
||||||
const selectedIds = new Set();
|
const selectedIds = new Set();
|
||||||
|
|
||||||
if (pageSizeSelect) {
|
if (pageSizeSelect) {
|
||||||
const initialSize = parseInt(pageSizeSelect.value);
|
const initialSize = parseInt(pageSizeSelect.value);
|
||||||
if (!isNaN(initialSize)) tableState.pageSize = initialSize;
|
if (!isNaN(initialSize)) {
|
||||||
|
tableState.pageSize = initialSize;
|
||||||
|
historyState.pageSize = initialSize;
|
||||||
|
}
|
||||||
pageSizeSelect.addEventListener('change', (e) => {
|
pageSizeSelect.addEventListener('change', (e) => {
|
||||||
const val = parseInt(e.target.value);
|
const val = parseInt(e.target.value);
|
||||||
if (!isNaN(val) && val > 0) {
|
if (!isNaN(val) && val > 0) {
|
||||||
tableState.pageSize = val;
|
tableState.pageSize = val;
|
||||||
|
historyState.pageSize = val;
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.applyDateFilter = function(){
|
window.applyDateFilter = function(){
|
||||||
tableState.startDate = startDateInput.value || '';
|
const start = startDateInput.value || '';
|
||||||
tableState.endDate = endDateInput.value || '';
|
const end = endDateInput.value || '';
|
||||||
|
tableState.startDate = start;
|
||||||
|
tableState.endDate = end;
|
||||||
|
historyState.startDate = start;
|
||||||
|
historyState.endDate = end;
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,12 +68,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (status === 'revised') return '<span class="badge bg-info">Revised</span>';
|
if (status === 'revised') return '<span class="badge bg-info">Revised</span>';
|
||||||
return '<span class="badge bg-warning text-dark">Pending</span>';
|
return '<span class="badge bg-warning text-dark">Pending</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function aksesBadge(akses){
|
function aksesBadge(akses){
|
||||||
if (akses){
|
if (akses){
|
||||||
return '<span class="badge bg-success">Umum</span>';
|
return '<span class="badge bg-success">Umum</span>';
|
||||||
} else{
|
|
||||||
return '<span class="badge bg-primary">Internal Unit</span>';
|
|
||||||
}
|
}
|
||||||
|
return '<span class="badge bg-primary">Internal Unit</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function safeText(val){
|
function safeText(val){
|
||||||
@ -72,6 +92,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
function updateSelectAllState(){
|
function updateSelectAllState(){
|
||||||
if (!selectAllCheckbox) return;
|
if (!selectAllCheckbox) return;
|
||||||
|
if (tableState.mode === 'history') {
|
||||||
|
selectAllCheckbox.checked = false;
|
||||||
|
selectAllCheckbox.indeterminate = false;
|
||||||
|
selectAllCheckbox.disabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const selectableIds = getSelectableIdsOnPage();
|
const selectableIds = getSelectableIdsOnPage();
|
||||||
if (selectableIds.length === 0) {
|
if (selectableIds.length === 0) {
|
||||||
selectAllCheckbox.checked = false;
|
selectAllCheckbox.checked = false;
|
||||||
@ -88,12 +115,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
function updateSelectionUI(){
|
function updateSelectionUI(){
|
||||||
const count = selectedIds.size;
|
const count = selectedIds.size;
|
||||||
if (selectedCountEl) selectedCountEl.textContent = String(count);
|
if (selectedCountEl) selectedCountEl.textContent = String(count);
|
||||||
if (bulkApproveBtn) bulkApproveBtn.disabled = count === 0;
|
if (bulkApproveBtn) bulkApproveBtn.disabled = count === 0 || tableState.mode === 'history';
|
||||||
if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0;
|
if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history';
|
||||||
updateSelectAllState();
|
updateSelectAllState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildRow(item){
|
function buildPendingRow(item){
|
||||||
const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||||||
const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||||||
const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
||||||
@ -102,6 +129,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const checked = selectedIds.has(id);
|
const checked = selectedIds.has(id);
|
||||||
const aksi = `
|
const aksi = `
|
||||||
<div class="d-flex gap-1">
|
<div class="d-flex gap-1">
|
||||||
|
<button class="btn btn-sm btn-primary" onclick="infoDok(this)"
|
||||||
|
data-file="${item.file}"
|
||||||
|
data-fileName="${item.nama_dokumen}"
|
||||||
|
data-id="${item.file_directory_id}"
|
||||||
|
data-no_dokumen="${item.no_dokumen || '-'}"
|
||||||
|
data-tanggal_terbit="${item.tanggal_terbit || '-'}"
|
||||||
|
data-permission_file="${item.permission_file || '-'}">
|
||||||
|
<i class="fa-solid fa-file-pdf"></i>
|
||||||
|
</button>
|
||||||
<button class="btn btn-sm btn-success" onclick="approvePending('${item.file_directory_id}', '${item.nama_dokumen || ''}')">
|
<button class="btn btn-sm btn-success" onclick="approvePending('${item.file_directory_id}', '${item.nama_dokumen || ''}')">
|
||||||
<i class="fa-solid fa-check"></i>
|
<i class="fa-solid fa-check"></i>
|
||||||
</button>
|
</button>
|
||||||
@ -140,67 +176,106 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildHistoryRow(item){
|
||||||
|
const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||||||
|
const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||||||
|
const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
||||||
|
const actionType = item?.action_type || '-';
|
||||||
|
return `
|
||||||
|
<tr>
|
||||||
|
<td>${safeText(item.no_dokumen)}</td>
|
||||||
|
<td>${aksesBadge(item?.permission_file)}</td>
|
||||||
|
<td><a href="#" class="file-link"
|
||||||
|
data-file="${item.file || ''}"
|
||||||
|
data-fileName="${item.nama_dokumen || '-'}"
|
||||||
|
data-id="${item.file_directory_id || ''}"
|
||||||
|
data-no_dokumen="${item.no_dokumen || '-'}"
|
||||||
|
data-tanggal_terbit="${item.tanggal_terbit || '-'}"
|
||||||
|
data-permission_file="${item.permission_file || '-'}">${safeText(item.nama_dokumen)}</a></td>
|
||||||
|
<td>${safeText(item.folder)}</td>
|
||||||
|
<td>${safeText(item.part)}</td>
|
||||||
|
<td><span class="badge bg-info">${actionType}</span></td>
|
||||||
|
<td class="text-nowrap">${tanggalTerbit}</td>
|
||||||
|
<td class="text-nowrap">${tanggalExp}</td>
|
||||||
|
<td class="text-nowrap">${tanggal}</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
function renderPagination(totalPages){
|
function renderPagination(totalPages){
|
||||||
|
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||||||
|
const paginationEl = tableState.mode === 'history' ? paginationHistoryEl : paginationPendingEl;
|
||||||
if (!paginationEl) return;
|
if (!paginationEl) return;
|
||||||
if (totalPages <= 1) {
|
if (totalPages <= 1) {
|
||||||
paginationEl.innerHTML = '';
|
paginationEl.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const maxButtons = 5;
|
const maxButtons = 5;
|
||||||
let start = Math.max(1, tableState.page - Math.floor(maxButtons/2));
|
let start = Math.max(1, activeState.page - Math.floor(maxButtons/2));
|
||||||
let end = Math.min(totalPages, start + maxButtons - 1);
|
let end = Math.min(totalPages, start + maxButtons - 1);
|
||||||
start = Math.max(1, end - maxButtons + 1);
|
start = Math.max(1, end - maxButtons + 1);
|
||||||
|
|
||||||
let buttons = '';
|
let buttons = '';
|
||||||
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${tableState.page === 1 ? 'disabled' : ''}>‹</button>`;
|
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${activeState.page === 1 ? 'disabled' : ''}>‹</button>`;
|
||||||
for (let i = start; i <= end; i++) {
|
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-sm ${i === activeState.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>`;
|
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="next" ${activeState.page === totalPages ? 'disabled' : ''}>›</button>`;
|
||||||
|
|
||||||
paginationEl.innerHTML = `
|
paginationEl.innerHTML = `
|
||||||
<div class="d-flex align-items-center gap-2 flex-wrap">
|
<div class="d-flex align-items-center gap-2 flex-wrap">
|
||||||
<div class="btn-group" role="group">${buttons}</div>
|
<div class="btn-group" role="group">${buttons}</div>
|
||||||
<span class="small text-muted">Halaman ${tableState.page} dari ${totalPages}</span>
|
<span class="small text-muted">Halaman ${activeState.page} dari ${totalPages}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paginationEl) {
|
function bindPagination(paginationEl, state){
|
||||||
|
if (!paginationEl) return;
|
||||||
paginationEl.addEventListener('click', (e) => {
|
paginationEl.addEventListener('click', (e) => {
|
||||||
const page = e.target.getAttribute('data-page');
|
const page = e.target.getAttribute('data-page');
|
||||||
if (!page) return;
|
if (!page) return;
|
||||||
if (page === 'prev' && tableState.page > 1) tableState.page--;
|
if (page === 'prev' && state.page > 1) state.page--;
|
||||||
else if (page === 'next') {
|
else if (page === 'next') {
|
||||||
if (tableState.page < tableState.lastPage) tableState.page++;
|
if (state.page < state.lastPage) state.page++;
|
||||||
} else {
|
} else {
|
||||||
tableState.page = parseInt(page);
|
state.page = parseInt(page);
|
||||||
}
|
}
|
||||||
fetchData();
|
fetchData();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
bindPagination(paginationPendingEl, tableState);
|
||||||
|
bindPagination(paginationHistoryEl, historyState);
|
||||||
|
|
||||||
function renderTable(){
|
function renderTable(){
|
||||||
const pageData = tableState.data || [];
|
const isHistoryMode = tableState.mode === 'history';
|
||||||
|
const activeState = isHistoryMode ? historyState : tableState;
|
||||||
|
const pageData = activeState.data || [];
|
||||||
|
const targetBody = isHistoryMode ? tbodyHistory : tbodyPending;
|
||||||
|
const rowBuilder = isHistoryMode ? buildHistoryRow : buildPendingRow;
|
||||||
|
const colSpan = isHistoryMode ? 9 : 12;
|
||||||
|
|
||||||
|
if (!targetBody) return;
|
||||||
|
|
||||||
if (pageData.length === 0) {
|
if (pageData.length === 0) {
|
||||||
tbody.innerHTML = `
|
targetBody.innerHTML = `
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="12" class="text-center text-muted py-4">
|
<td colspan="${colSpan}" class="text-center text-muted py-4">
|
||||||
Tidak ada data
|
Tidak ada data
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
tbody.innerHTML = pageData.map(buildRow).join('');
|
targetBody.innerHTML = pageData.map(rowBuilder).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
const from = tableState.total === 0 ? 0 : ((tableState.page - 1) * tableState.pageSize) + 1;
|
const from = activeState.total === 0 ? 0 : ((activeState.page - 1) * activeState.pageSize) + 1;
|
||||||
const to = Math.min(((tableState.page - 1) * tableState.pageSize) + pageData.length, tableState.total);
|
const to = Math.min(((activeState.page - 1) * activeState.pageSize) + pageData.length, activeState.total);
|
||||||
if (summaryEl) {
|
if (summaryEl) {
|
||||||
summaryEl.textContent = tableState.total ? `Menampilkan ${from} - ${to} dari ${tableState.total} data` : 'Tidak ada data';
|
summaryEl.textContent = activeState.total ? `Menampilkan ${from} - ${to} dari ${activeState.total} data` : 'Tidak ada data';
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPagination(tableState.lastPage || 1);
|
renderPagination(activeState.lastPage || 1);
|
||||||
updateSelectionUI();
|
updateSelectionUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,8 +283,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
window.debouncedTableSearch = function(value){
|
window.debouncedTableSearch = function(value){
|
||||||
clearTimeout(searchDebounce);
|
clearTimeout(searchDebounce);
|
||||||
searchDebounce = setTimeout(() => {
|
searchDebounce = setTimeout(() => {
|
||||||
tableState.search = value.trim();
|
const keyword = value.trim();
|
||||||
|
tableState.search = keyword;
|
||||||
|
historyState.search = keyword;
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}, 250);
|
}, 250);
|
||||||
}
|
}
|
||||||
@ -218,29 +296,77 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
tableState.search = '';
|
tableState.search = '';
|
||||||
tableState.startDate = '';
|
tableState.startDate = '';
|
||||||
tableState.endDate = '';
|
tableState.endDate = '';
|
||||||
document.getElementById('tableSearch').value = '';
|
historyState.search = '';
|
||||||
startDateInput.value = '';
|
historyState.startDate = '';
|
||||||
endDateInput.value = '';
|
historyState.endDate = '';
|
||||||
|
const tableSearch = document.getElementById('tableSearch');
|
||||||
|
if (tableSearch) tableSearch.value = '';
|
||||||
|
if (startDateInput) startDateInput.value = '';
|
||||||
|
if (endDateInput) endDateInput.value = '';
|
||||||
selectedIds.clear();
|
selectedIds.clear();
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTabUI(){
|
||||||
|
if (tabsEl) {
|
||||||
|
tabsEl.querySelectorAll('.nav-link').forEach((btn) => {
|
||||||
|
btn.classList.toggle('active', btn.getAttribute('data-mode') === tableState.mode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.textContent = tableState.mode === 'history' ? 'Log History' : 'Data Pending';
|
||||||
|
}
|
||||||
|
if (tabPendingEl && tabHistoryEl) {
|
||||||
|
tabPendingEl.classList.toggle('d-none', tableState.mode === 'history');
|
||||||
|
tabHistoryEl.classList.toggle('d-none', tableState.mode !== 'history');
|
||||||
|
}
|
||||||
|
if (pendingBulkActionsEl) {
|
||||||
|
pendingBulkActionsEl.classList.toggle('d-none', tableState.mode === 'history');
|
||||||
|
}
|
||||||
|
updateSelectionUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tabsEl) {
|
||||||
|
tabsEl.addEventListener('click', (e) => {
|
||||||
|
const btn = e.target.closest('[data-mode]');
|
||||||
|
if (!btn) return;
|
||||||
|
const mode = btn.getAttribute('data-mode');
|
||||||
|
if (!mode || mode === tableState.mode) return;
|
||||||
|
tableState.mode = mode;
|
||||||
|
if (mode === 'history') {
|
||||||
|
historyState.page = 1;
|
||||||
|
} else {
|
||||||
|
tableState.page = 1;
|
||||||
|
}
|
||||||
|
updateTabUI();
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function fetchData(){
|
function fetchData(){
|
||||||
if (summaryEl) summaryEl.textContent = 'Memuat data...';
|
if (summaryEl) summaryEl.textContent = 'Memuat data...';
|
||||||
|
|
||||||
|
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
page: tableState.page,
|
page: activeState.page,
|
||||||
per_page: tableState.pageSize,
|
per_page: activeState.pageSize,
|
||||||
keyword: tableState.search || '',
|
keyword: activeState.search || '',
|
||||||
start_date: tableState.startDate || '',
|
start_date: activeState.startDate || '',
|
||||||
end_date: tableState.endDate || ''
|
end_date: activeState.endDate || ''
|
||||||
});
|
});
|
||||||
fetch(`/datatable/pending-file?${params.toString()}`)
|
|
||||||
|
const endpoint = tableState.mode === 'history'
|
||||||
|
? `/data/log-dokumen?${params.toString()}`
|
||||||
|
: `/datatable/pending-file?${params.toString()}`;
|
||||||
|
|
||||||
|
fetch(endpoint)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
tableState.data = data?.data || [];
|
activeState.data = data?.data || [];
|
||||||
tableState.lastPage = data?.pagination?.last_page || 1;
|
activeState.lastPage = data?.pagination?.last_page || 1;
|
||||||
tableState.total = data?.pagination?.total || 0;
|
activeState.total = data?.pagination?.total || 0;
|
||||||
renderTable();
|
renderTable();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@ -278,7 +404,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
showConfirmButton: false
|
showConfirmButton: false
|
||||||
});
|
});
|
||||||
selectedIds.delete(String(id));
|
selectedIds.delete(String(id));
|
||||||
countData()
|
countData();
|
||||||
fetchData();
|
fetchData();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
@ -335,7 +461,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
showConfirmButton: false
|
showConfirmButton: false
|
||||||
});
|
});
|
||||||
selectedIds.delete(String(id));
|
selectedIds.delete(String(id));
|
||||||
countData()
|
countData();
|
||||||
fetchData();
|
fetchData();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
@ -346,19 +472,41 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.infoReject = function(id, fileName){
|
|
||||||
const item = id;
|
window.infoDok = function(e){
|
||||||
const revision = item?.revision ? String(item.revision) : 'Tidak ada catatan revisi.';
|
let fileUrl =$(e).data('file');
|
||||||
Swal.fire({
|
let noDokumen = $(e).data('no_dokumen');
|
||||||
title: 'Catatan Revisi',
|
let tanggalTerbit = $(e).data('tanggal_terbit');
|
||||||
text: revision,
|
let permissionFile = $(e).data('permission_file');
|
||||||
icon: 'info',
|
let fileName = $(e).data('fileName');
|
||||||
confirmButtonText: 'Tutup'
|
currentFile = fileUrl;
|
||||||
});
|
idDirectory = $(e).data('id');
|
||||||
|
|
||||||
|
const titleEl = document.getElementById('confirm_preview_file');
|
||||||
|
if (titleEl) titleEl.textContent = fileName;
|
||||||
|
|
||||||
|
const noEl = document.getElementById('confirm-upload-dokumen');
|
||||||
|
if (noEl) noEl.textContent = noDokumen;
|
||||||
|
|
||||||
|
const tglEl = document.getElementById('confirm-time-dokumen');
|
||||||
|
if (tglEl) tglEl.textContent = tanggalTerbit;
|
||||||
|
|
||||||
|
const permEl = document.getElementById('confirm-permission');
|
||||||
|
if (permEl) {
|
||||||
|
const publicDoc = isPublic(permissionFile);
|
||||||
|
permEl.textContent = publicDoc ? 'Umum' : 'Internal Unit';
|
||||||
|
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
|
||||||
|
}
|
||||||
|
let previewBox = document.getElementById('file-preview');
|
||||||
|
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
|
||||||
|
<div id="pdfPages"></div>
|
||||||
|
</div>`;
|
||||||
|
openPreview(idDirectory);
|
||||||
|
$("#previewModal").modal('show');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tbody) {
|
if (tbodyPending) {
|
||||||
tbody.addEventListener('change', (e) => {
|
tbodyPending.addEventListener('change', (e) => {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
if (!target.classList.contains('row-select')) return;
|
if (!target.classList.contains('row-select')) return;
|
||||||
const id = target.getAttribute('data-id');
|
const id = target.getAttribute('data-id');
|
||||||
@ -424,7 +572,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
timer: 1500,
|
timer: 1500,
|
||||||
showConfirmButton: false
|
showConfirmButton: false
|
||||||
});
|
});
|
||||||
countData()
|
countData();
|
||||||
fetchData();
|
fetchData();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
@ -437,57 +585,51 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTabUI();
|
||||||
fetchData();
|
fetchData();
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('click', function(e){
|
document.addEventListener('click', function(e){
|
||||||
if(e.target.matches('.file-link')){
|
if(e.target.matches('.file-link')){
|
||||||
|
e.preventDefault();
|
||||||
|
let fileUrl = e.target.getAttribute('data-file');
|
||||||
|
let noDokumen = e.target.getAttribute('data-no_dokumen');
|
||||||
|
let tanggalTerbit = e.target.getAttribute('data-tanggal_terbit');
|
||||||
|
let permissionFile = e.target.getAttribute('data-permission_file');
|
||||||
|
let fileName = e.target.getAttribute('data-fileName');
|
||||||
|
currentFile = fileUrl;
|
||||||
|
idDirectory = e.target.getAttribute('data-id');
|
||||||
|
|
||||||
e.preventDefault();
|
const titleEl = document.getElementById('confirm_preview_file');
|
||||||
let fileUrl = e.target.getAttribute('data-file');
|
if (titleEl) titleEl.textContent = fileName;
|
||||||
let noDokumen = e.target.getAttribute('data-no_dokumen')
|
|
||||||
let tanggalTerbit = e.target.getAttribute('data-tanggal_terbit')
|
|
||||||
let permissionFile = e.target.getAttribute('data-permission_file')
|
|
||||||
let fileName = e.target.getAttribute('data-fileName')
|
|
||||||
currentFile = fileUrl;
|
|
||||||
idDirectory = e.target.getAttribute('data-id');
|
|
||||||
|
|
||||||
|
const noEl = document.getElementById('confirm-upload-dokumen');
|
||||||
|
if (noEl) noEl.textContent = noDokumen;
|
||||||
|
|
||||||
const titleEl = document.getElementById('confirm_preview_file');
|
const tglEl = document.getElementById('confirm-time-dokumen');
|
||||||
if (titleEl) titleEl.textContent = fileName;
|
if (tglEl) tglEl.textContent = tanggalTerbit;
|
||||||
|
|
||||||
// set footer info
|
const permEl = document.getElementById('confirm-permission');
|
||||||
const noEl = document.getElementById('confirm-upload-dokumen');
|
if (permEl) {
|
||||||
if (noEl) noEl.textContent = noDokumen;
|
const publicDoc = isPublic(permissionFile);
|
||||||
|
permEl.textContent = publicDoc ? 'Umum' : 'Internal Unit';
|
||||||
const tglEl = document.getElementById('confirm-time-dokumen');
|
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
|
||||||
|
|
||||||
if (tglEl) tglEl.textContent = tanggalTerbit;
|
|
||||||
|
|
||||||
const permEl = document.getElementById('confirm-permission');
|
|
||||||
if (permEl) {
|
|
||||||
const publicDoc = isPublic(permissionFile);
|
|
||||||
permEl.textContent = publicDoc ? 'Umum' : 'Internal Unit';
|
|
||||||
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
|
|
||||||
}
|
|
||||||
let previewBox = document.getElementById('file-preview');
|
|
||||||
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
|
|
||||||
<div id="pdfPages"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
openPreview(idDirectory);
|
|
||||||
$("#previewModal").modal('show')
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(e.target.matches('#btn-view-full')){
|
|
||||||
window.open(`/full-preview/${idDirectory}`, '_blank');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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 previewBox = document.getElementById('file-preview');
|
||||||
|
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
|
||||||
|
<div id="pdfPages"></div>
|
||||||
|
</div>`;
|
||||||
|
openPreview(idDirectory);
|
||||||
|
$("#previewModal").modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(e.target.matches('#btn-view-full')){
|
||||||
|
window.open(`/full-preview/${idDirectory}`, '_blank');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function isPublic(permissionVal){
|
||||||
|
if(permissionVal === null || permissionVal === undefined) return false;
|
||||||
|
const val = String(permissionVal).toLowerCase();
|
||||||
|
return val === '1' || val === 'true' || val === 'iya' || val === 'yes';
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '' };
|
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '', mode: 'pengajuan' };
|
||||||
const tbody = document.getElementById('tablePengajuanFile');
|
const historyState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '', mode: 'history' };
|
||||||
const paginationEl = document.getElementById('paginationControls');
|
const tbodyPengajuan = document.getElementById('tablePengajuanFile');
|
||||||
|
const tbodyHistory = document.getElementById('tableHistoryFile');
|
||||||
|
const paginationPengajuan = document.getElementById('paginationPengajuan');
|
||||||
|
const paginationHistory = document.getElementById('paginationHistory');
|
||||||
const summaryEl = document.getElementById('tableSummary');
|
const summaryEl = document.getElementById('tableSummary');
|
||||||
const pageSizeSelect = document.getElementById('tablePageSize');
|
const pageSizeSelect = document.getElementById('tablePageSize');
|
||||||
const startDateInput = document.getElementById('startDate');
|
const startDateInput = document.getElementById('startDate');
|
||||||
const endDateInput = document.getElementById('endDate');
|
const endDateInput = document.getElementById('endDate');
|
||||||
|
const tabsEl = document.getElementById('pengajuanTabs');
|
||||||
|
const titleEl = document.getElementById('pengajuanTitle');
|
||||||
|
const tabPengajuanEl = document.getElementById('tabPengajuan');
|
||||||
|
const tabHistoryEl = document.getElementById('tabHistory');
|
||||||
|
const formCreate = document.getElementById('formFile');
|
||||||
|
const modalCreate = document.getElementById('modalCreateFile');
|
||||||
|
let colCount = 1;
|
||||||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
||||||
const editForm = document.getElementById('formEditPengajuanFile');
|
const editForm = document.getElementById('formEditPengajuanFile');
|
||||||
const editUnitSelect = $('#edit_id_unit_kerja');
|
const editUnitSelect = $('#edit_id_unit_kerja');
|
||||||
@ -13,21 +23,31 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
if (pageSizeSelect) {
|
if (pageSizeSelect) {
|
||||||
const initialSize = parseInt(pageSizeSelect.value);
|
const initialSize = parseInt(pageSizeSelect.value);
|
||||||
if (!isNaN(initialSize)) tableState.pageSize = initialSize;
|
if (!isNaN(initialSize)) {
|
||||||
|
tableState.pageSize = initialSize;
|
||||||
|
historyState.pageSize = initialSize;
|
||||||
|
}
|
||||||
pageSizeSelect.addEventListener('change', (e) => {
|
pageSizeSelect.addEventListener('change', (e) => {
|
||||||
const val = parseInt(e.target.value);
|
const val = parseInt(e.target.value);
|
||||||
if (!isNaN(val) && val > 0) {
|
if (!isNaN(val) && val > 0) {
|
||||||
tableState.pageSize = val;
|
tableState.pageSize = val;
|
||||||
|
historyState.pageSize = val;
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.applyDateFilter = function(){
|
window.applyDateFilter = function(){
|
||||||
tableState.startDate = startDateInput.value || '';
|
const start = startDateInput.value || '';
|
||||||
tableState.endDate = endDateInput.value || '';
|
const end = endDateInput.value || '';
|
||||||
|
tableState.startDate = start;
|
||||||
|
tableState.endDate = end;
|
||||||
|
historyState.startDate = start;
|
||||||
|
historyState.endDate = end;
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +65,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||||||
let tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
let tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||||||
let tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
let tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
||||||
|
const isApproved = item?.status_action === 'approved';
|
||||||
|
const isRejected = item?.status_action === 'rejected';
|
||||||
|
const showEdit = !isApproved;
|
||||||
|
const showInfo = isRejected;
|
||||||
const aksi = `
|
const aksi = `
|
||||||
<div class="d-flex gap-1">
|
<div class="d-flex gap-1">
|
||||||
<button href="#" class="btn btn-sm btn-primary" onclick="infoDok(this)"
|
<button href="#" class="btn btn-sm btn-primary" onclick="infoDok(this)"
|
||||||
@ -56,13 +80,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
data-permission_file="${item.permission_file || '-'}">
|
data-permission_file="${item.permission_file || '-'}">
|
||||||
<i class="fa-solid fa-file-pdf"></i>
|
<i class="fa-solid fa-file-pdf"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm btn-info" onclick="infoReject('${item.file_directory_id}')">
|
${showInfo ? `
|
||||||
<i class="fa-solid fa-circle-info"></i>
|
<button class="btn btn-sm btn-info" onclick="infoReject('${item.file_directory_id}')">
|
||||||
</button>
|
<i class="fa-solid fa-circle-info"></i>
|
||||||
<button class="btn btn-sm btn-primary" onclick="editFileReject('${item.file_directory_id}')">
|
</button>
|
||||||
<i class="fa-solid fa-pen-to-square"></i>
|
` : ''}
|
||||||
</button>
|
${showEdit ? `
|
||||||
|
<button class="btn btn-sm btn-primary" onclick="editFileReject('${item.file_directory_id}')">
|
||||||
|
<i class="fa-solid fa-pen-to-square"></i>
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
return `
|
return `
|
||||||
@ -71,10 +98,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<td>${item.no_dokumen || '-'}</td>
|
<td>${item.no_dokumen || '-'}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-sm
|
<button class="btn btn-sm
|
||||||
${item?.status_action === "rejected" ? 'btn-danger' :
|
${item?.status_action === "approved" ? 'btn-success' :
|
||||||
|
item?.status_action === "rejected" ? 'btn-danger' :
|
||||||
item?.status_action === "revised" ? 'btn-info' :
|
item?.status_action === "revised" ? 'btn-info' :
|
||||||
'btn-warning'}">
|
'btn-warning'}">
|
||||||
${item?.status_action === "rejected" ? 'Rejected' :
|
${item?.status_action === "approved" ? 'Approved' :
|
||||||
|
item?.status_action === "rejected" ? 'Rejected' :
|
||||||
item?.status_action === "revised" ? 'Revised' :
|
item?.status_action === "revised" ? 'Revised' :
|
||||||
'Pending'}
|
'Pending'}
|
||||||
</button>
|
</button>
|
||||||
@ -96,6 +125,32 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildHistoryRow(item){
|
||||||
|
const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||||||
|
const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||||||
|
const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
||||||
|
const actionType = item?.action_type || '-';
|
||||||
|
return `
|
||||||
|
<tr>
|
||||||
|
<td>${item.no_dokumen || '-'}</td>
|
||||||
|
<td>${aksesBadge(item?.permission_file)}</td>
|
||||||
|
<td><a href="#" class="file-link"
|
||||||
|
data-file="${item.file || ''}"
|
||||||
|
data-fileName="${item.nama_dokumen || '-'}"
|
||||||
|
data-id="${item.file_directory_id || ''}"
|
||||||
|
data-no_dokumen="${item.no_dokumen || '-'}"
|
||||||
|
data-tanggal_terbit="${item.tanggal_terbit || '-'}"
|
||||||
|
data-permission_file="${item.permission_file || '-'}">${item.nama_dokumen || '-'}</a></td>
|
||||||
|
<td>${item.folder || '-'}</td>
|
||||||
|
<td>${item.part || '-'}</td>
|
||||||
|
<td><span class="badge bg-info">${item.action_type}</span></td>
|
||||||
|
<td class="text-nowrap">${tanggalTerbit}</td>
|
||||||
|
<td class="text-nowrap">${tanggalExp}</td>
|
||||||
|
<td class="text-nowrap">${tanggal}</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
function aksesBadge(akses){
|
function aksesBadge(akses){
|
||||||
if (akses){
|
if (akses){
|
||||||
return '<span class="badge bg-success">Umum</span>';
|
return '<span class="badge bg-success">Umum</span>';
|
||||||
@ -109,74 +164,87 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderPagination(totalPages){
|
function renderPagination(totalPages){
|
||||||
|
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||||||
|
const paginationEl = tableState.mode === 'history' ? paginationHistory : paginationPengajuan;
|
||||||
if (!paginationEl) return;
|
if (!paginationEl) return;
|
||||||
if (totalPages <= 1) {
|
if (totalPages <= 1) {
|
||||||
paginationEl.innerHTML = '';
|
paginationEl.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const maxButtons = 5;
|
const maxButtons = 5;
|
||||||
let start = Math.max(1, tableState.page - Math.floor(maxButtons/2));
|
let start = Math.max(1, activeState.page - Math.floor(maxButtons/2));
|
||||||
let end = Math.min(totalPages, start + maxButtons - 1);
|
let end = Math.min(totalPages, start + maxButtons - 1);
|
||||||
start = Math.max(1, end - maxButtons + 1);
|
start = Math.max(1, end - maxButtons + 1);
|
||||||
|
|
||||||
let buttons = '';
|
let buttons = '';
|
||||||
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${tableState.page === 1 ? 'disabled' : ''}>‹</button>`;
|
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${activeState.page === 1 ? 'disabled' : ''}>‹</button>`;
|
||||||
for (let i = start; i <= end; i++) {
|
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-sm ${i === activeState.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>`;
|
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="next" ${activeState.page === totalPages ? 'disabled' : ''}>›</button>`;
|
||||||
|
|
||||||
paginationEl.innerHTML = `
|
paginationEl.innerHTML = `
|
||||||
<div class="d-flex align-items-center gap-2 flex-wrap">
|
<div class="d-flex align-items-center gap-2 flex-wrap">
|
||||||
<div class="btn-group" role="group">${buttons}</div>
|
<div class="btn-group" role="group">${buttons}</div>
|
||||||
<span class="small text-muted">Halaman ${tableState.page} dari ${totalPages}</span>
|
<span class="small text-muted">Halaman ${activeState.page} dari ${totalPages}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paginationEl) {
|
function bindPagination(paginationEl, state){
|
||||||
|
if (!paginationEl) return;
|
||||||
paginationEl.addEventListener('click', (e) => {
|
paginationEl.addEventListener('click', (e) => {
|
||||||
const page = e.target.getAttribute('data-page');
|
const page = e.target.getAttribute('data-page');
|
||||||
if (!page) return;
|
if (!page) return;
|
||||||
if (page === 'prev' && tableState.page > 1) tableState.page--;
|
if (page === 'prev' && state.page > 1) state.page--;
|
||||||
else if (page === 'next') {
|
else if (page === 'next') {
|
||||||
if (tableState.page < tableState.lastPage) tableState.page++;
|
if (state.page < state.lastPage) state.page++;
|
||||||
} else {
|
} else {
|
||||||
tableState.page = parseInt(page);
|
state.page = parseInt(page);
|
||||||
}
|
}
|
||||||
fetchData();
|
fetchData();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
bindPagination(paginationPengajuan, tableState);
|
||||||
|
bindPagination(paginationHistory, historyState);
|
||||||
|
|
||||||
function renderTable(){
|
function renderTable(){
|
||||||
const pageData = tableState.data || [];
|
const isHistoryMode = tableState.mode === 'history';
|
||||||
|
const activeState = isHistoryMode ? historyState : tableState;
|
||||||
|
const pageData = activeState.data || [];
|
||||||
|
const targetBody = isHistoryMode ? tbodyHistory : tbodyPengajuan;
|
||||||
|
const colSpan = isHistoryMode ? 9 : 10;
|
||||||
|
const rowBuilder = isHistoryMode ? buildHistoryRow : buildRow;
|
||||||
if (pageData.length === 0) {
|
if (pageData.length === 0) {
|
||||||
tbody.innerHTML = `
|
targetBody.innerHTML = `
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="10" class="text-center text-muted py-4">
|
<td colspan="${colSpan}" class="text-center text-muted py-4">
|
||||||
Tidak ada data
|
Tidak ada data
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
tbody.innerHTML = pageData.map(buildRow).join('');
|
targetBody.innerHTML = pageData.map(rowBuilder).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
const from = tableState.total === 0 ? 0 : ((tableState.page - 1) * tableState.pageSize) + 1;
|
const from = activeState.total === 0 ? 0 : ((activeState.page - 1) * activeState.pageSize) + 1;
|
||||||
const to = Math.min(((tableState.page - 1) * tableState.pageSize) + pageData.length, tableState.total);
|
const to = Math.min(((activeState.page - 1) * activeState.pageSize) + pageData.length, activeState.total);
|
||||||
if (summaryEl) {
|
if (summaryEl) {
|
||||||
summaryEl.textContent = tableState.total ? `Menampilkan ${from} - ${to} dari ${tableState.total} data` : 'Tidak ada data';
|
summaryEl.textContent = activeState.total ? `Menampilkan ${from} - ${to} dari ${activeState.total} data` : 'Tidak ada data';
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPagination(tableState.lastPage || 1);
|
renderPagination(activeState.lastPage || 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let searchDebounce;
|
let searchDebounce;
|
||||||
window.debouncedTableSearch = function(value){
|
window.debouncedTableSearch = function(value){
|
||||||
clearTimeout(searchDebounce);
|
clearTimeout(searchDebounce);
|
||||||
searchDebounce = setTimeout(() => {
|
searchDebounce = setTimeout(() => {
|
||||||
tableState.search = value.trim();
|
const keyword = value.trim();
|
||||||
|
tableState.search = keyword;
|
||||||
|
historyState.search = keyword;
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}, 250);
|
}, 250);
|
||||||
}
|
}
|
||||||
@ -185,28 +253,64 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
tableState.search = '';
|
tableState.search = '';
|
||||||
tableState.startDate = '';
|
tableState.startDate = '';
|
||||||
tableState.endDate = '';
|
tableState.endDate = '';
|
||||||
|
historyState.search = '';
|
||||||
|
historyState.startDate = '';
|
||||||
|
historyState.endDate = '';
|
||||||
document.getElementById('tableSearch').value = '';
|
document.getElementById('tableSearch').value = '';
|
||||||
startDateInput.value = '';
|
startDateInput.value = '';
|
||||||
endDateInput.value = '';
|
endDateInput.value = '';
|
||||||
tableState.page = 1;
|
tableState.page = 1;
|
||||||
|
historyState.page = 1;
|
||||||
fetchData();
|
fetchData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTabUI(){
|
||||||
|
if (tabsEl) {
|
||||||
|
tabsEl.querySelectorAll('.nav-link').forEach((btn) => {
|
||||||
|
btn.classList.toggle('active', btn.getAttribute('data-mode') === tableState.mode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (titleEl) {
|
||||||
|
titleEl.textContent = tableState.mode === 'history' ? 'Log History' : 'Data Pengajuan';
|
||||||
|
}
|
||||||
|
if (tabPengajuanEl && tabHistoryEl) {
|
||||||
|
tabPengajuanEl.classList.toggle('d-none', tableState.mode === 'history');
|
||||||
|
tabHistoryEl.classList.toggle('d-none', tableState.mode !== 'history');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tabsEl) {
|
||||||
|
tabsEl.addEventListener('click', (e) => {
|
||||||
|
const btn = e.target.closest('[data-mode]');
|
||||||
|
if (!btn) return;
|
||||||
|
const mode = btn.getAttribute('data-mode');
|
||||||
|
if (!mode || mode === tableState.mode) return;
|
||||||
|
tableState.mode = mode;
|
||||||
|
tableState.page = 1;
|
||||||
|
updateTabUI();
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function fetchData(){
|
function fetchData(){
|
||||||
if (summaryEl) summaryEl.textContent = 'Memuat data...';
|
if (summaryEl) summaryEl.textContent = 'Memuat data...';
|
||||||
|
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
page: tableState.page,
|
page: activeState.page,
|
||||||
per_page: tableState.pageSize,
|
per_page: activeState.pageSize,
|
||||||
keyword: tableState.search || '',
|
keyword: activeState.search || '',
|
||||||
start_date: tableState.startDate || '',
|
start_date: activeState.startDate || '',
|
||||||
end_date: tableState.endDate || ''
|
end_date: activeState.endDate || ''
|
||||||
});
|
});
|
||||||
fetch(`/datatable/pengajuan-file?${params.toString()}`)
|
const endpoint = tableState.mode === 'history'
|
||||||
|
? `/data/log-dokumen?${params.toString()}`
|
||||||
|
: `/datatable/pengajuan-file?${params.toString()}`;
|
||||||
|
fetch(endpoint)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
tableState.data = data?.data || [];
|
activeState.data = data?.data || [];
|
||||||
tableState.lastPage = data?.pagination?.last_page || 1;
|
activeState.lastPage = data?.pagination?.last_page || 1;
|
||||||
tableState.total = data?.pagination?.total || 0;
|
activeState.total = data?.pagination?.total || 0;
|
||||||
renderTable();
|
renderTable();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@ -339,7 +443,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const tglEl = document.getElementById('edit_tanggal_terbit');
|
const tglEl = document.getElementById('edit_tanggal_terbit');
|
||||||
const tglExpiredEl = document.getElementById('edit_tgl_expired');
|
const tglExpiredEl = document.getElementById('edit_tgl_expired');
|
||||||
const hasExpiredEl = document.getElementById('edit_has_expired');
|
const hasExpiredEl = document.getElementById('edit_has_expired');
|
||||||
const expiredFieldEl = document.getElementById('edit_expired_field');
|
|
||||||
const currentFileEl = document.getElementById('edit_current_file');
|
const currentFileEl = document.getElementById('edit_current_file');
|
||||||
const permYes = document.getElementById('edit_perm_yes');
|
const permYes = document.getElementById('edit_perm_yes');
|
||||||
const permNo = document.getElementById('edit_perm_no');
|
const permNo = document.getElementById('edit_perm_no');
|
||||||
@ -355,10 +458,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
permYes.checked = isPublic;
|
permYes.checked = isPublic;
|
||||||
permNo.checked = !isPublic;
|
permNo.checked = !isPublic;
|
||||||
}
|
}
|
||||||
if (hasExpiredEl && expiredFieldEl) {
|
if (hasExpiredEl && tglExpiredEl) {
|
||||||
const hasExpired = !!item.tgl_expired;
|
const hasExpired = !!item.tgl_expired;
|
||||||
hasExpiredEl.checked = hasExpired;
|
hasExpiredEl.checked = hasExpired;
|
||||||
expiredFieldEl.classList.toggle('d-none', !hasExpired);
|
syncEditExpiredField();
|
||||||
}
|
}
|
||||||
if (currentFileEl) {
|
if (currentFileEl) {
|
||||||
const displayName = item.fileName || (item.file ? String(item.file).split('/').pop() : '');
|
const displayName = item.fileName || (item.file ? String(item.file).split('/').pop() : '');
|
||||||
@ -393,19 +496,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncEditExpiredField() {
|
||||||
|
const editHasExpired = document.getElementById('edit_has_expired');
|
||||||
|
const editExpiredInput = document.getElementById('edit_tgl_expired');
|
||||||
|
if (!editHasExpired || !editExpiredInput) return;
|
||||||
|
editExpiredInput.disabled = !editHasExpired.checked;
|
||||||
|
if (!editHasExpired.checked) {
|
||||||
|
editExpiredInput.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const editHasExpired = document.getElementById('edit_has_expired');
|
const editHasExpired = document.getElementById('edit_has_expired');
|
||||||
if (editHasExpired) {
|
if (editHasExpired) {
|
||||||
editHasExpired.addEventListener('change', () => {
|
editHasExpired.addEventListener('change', syncEditExpiredField);
|
||||||
const targetId = editHasExpired.getAttribute('data-target');
|
|
||||||
const container = targetId ? document.getElementById(targetId) : null;
|
|
||||||
if (container) {
|
|
||||||
container.classList.toggle('d-none', !editHasExpired.checked);
|
|
||||||
if (!editHasExpired.checked) {
|
|
||||||
const input = container.querySelector('input[type="date"]');
|
|
||||||
if (input) input.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editForm) {
|
if (editForm) {
|
||||||
@ -449,7 +552,270 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initEditSelects();
|
initEditSelects();
|
||||||
|
updateTabUI();
|
||||||
fetchData();
|
fetchData();
|
||||||
|
|
||||||
|
// ===== Upload baru (seperti dataUnit) =====
|
||||||
|
document.addEventListener('change', function(e){
|
||||||
|
if(!e.target.classList.contains('toggle-expired')) return;
|
||||||
|
const targetId = e.target.getAttribute('data-target');
|
||||||
|
if(!targetId) return;
|
||||||
|
const fieldWrap = document.getElementById(targetId);
|
||||||
|
const input = fieldWrap?.querySelector('input');
|
||||||
|
if (input) input.disabled = !e.target.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
function resetCreateForm(){
|
||||||
|
colCount = 1;
|
||||||
|
const colAdd = document.getElementById('col_add_fileV2');
|
||||||
|
if (colAdd) colAdd.innerHTML = '';
|
||||||
|
if (formCreate) {
|
||||||
|
formCreate.reset();
|
||||||
|
$(formCreate).find('select').val(null).trigger('change');
|
||||||
|
$(formCreate).find('input[type="file"]').val('');
|
||||||
|
$(formCreate).find('.file-name').addClass('d-none').text('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectOptionUnitKerjaV1(localCol){
|
||||||
|
const selectUnit = $(`#select_id_unit_kerja_${localCol}`);
|
||||||
|
const selectSubUnit = $(`#select_id_sub_unit_kerja_${localCol}`);
|
||||||
|
|
||||||
|
selectUnit.select2({
|
||||||
|
placeholder: '-- Pilih Unit Kerja --',
|
||||||
|
allowClear:true,
|
||||||
|
width: '100%',
|
||||||
|
dropdownParent: selectUnit.parent(),
|
||||||
|
ajax:{
|
||||||
|
url : '/select-unit-kerja-mapping',
|
||||||
|
dataType: 'json',
|
||||||
|
delay: 250,
|
||||||
|
data: function(params){
|
||||||
|
return { q: params.term }
|
||||||
|
},
|
||||||
|
processResults: function(data){
|
||||||
|
return {
|
||||||
|
results : (data?.data || []).map(item => ({
|
||||||
|
id: item.id+'/'+item.name,
|
||||||
|
text: item.name,
|
||||||
|
sub_units: item.sub_unit_kerja
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cache: true,
|
||||||
|
},
|
||||||
|
minimumInputLength: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
selectSubUnit.select2({
|
||||||
|
placeholder: '-- Pilih Sub Unit Kerja --',
|
||||||
|
allowClear: true,
|
||||||
|
width: '100%',
|
||||||
|
dropdownParent: selectSubUnit.parent()
|
||||||
|
});
|
||||||
|
|
||||||
|
selectUnit.on('select2:select', function (e) {
|
||||||
|
const data = e.params.data;
|
||||||
|
selectSubUnit.empty().append('<option value="" disabled selected>-- Pilih Sub Unit Kerja --</option>');
|
||||||
|
if (data.sub_units && data.sub_units.length > 0) {
|
||||||
|
data.sub_units.forEach(sub => {
|
||||||
|
selectSubUnit.append(`<option value="${sub.id}/${sub.name}">${sub.name}</option>`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addFormV2 = function(){
|
||||||
|
const col = document.getElementById('col_add_fileV2');
|
||||||
|
if (!col) return;
|
||||||
|
const katDok = Array.isArray(window.katDok) ? window.katDok : [];
|
||||||
|
const katOptions = katDok.map(k => `<option value="${k.master_kategori_directory_id}/${k.nama_kategori_directory}">${k.nama_kategori_directory}</option>`).join('');
|
||||||
|
|
||||||
|
let html = `
|
||||||
|
<div class="row g-3 align-items-start" id="col-${colCount}">
|
||||||
|
<hr class="my-3" />
|
||||||
|
<div class="col-12 d-flex justify-content-end">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-sm btn-danger"
|
||||||
|
onclick="removeCol(${colCount})">
|
||||||
|
<i class="fa-solid fa-trash"></i> Hapus
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Unit <span class="text-danger">*</span></label>
|
||||||
|
<select class="form-select"
|
||||||
|
name="data[${colCount}][id_unit_kerja]"
|
||||||
|
id="select_id_unit_kerja_${colCount}"
|
||||||
|
required>
|
||||||
|
<option value="" disabled selected>Pilih Unit</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Sub Unit <span class="text-danger">*</span></label>
|
||||||
|
<select class="form-select"
|
||||||
|
name="data[${colCount}][id_sub_unit_kerja]"
|
||||||
|
id="select_id_sub_unit_kerja_${colCount}"
|
||||||
|
required>
|
||||||
|
<option value="" disabled selected>Pilih Sub Unit</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Kategori Dokumen <span class="text-danger">*</span></label>
|
||||||
|
<select class="form-select"
|
||||||
|
name="data[${colCount}][master_kategori_directory_id]"
|
||||||
|
id="select_kategori_${colCount}"
|
||||||
|
required>
|
||||||
|
<option value="" disabled selected>Pilih Kategori</option>
|
||||||
|
${katOptions}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Nomor Dokumen</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text">#</span>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="data[${colCount}][no_dokumen]"
|
||||||
|
placeholder="Contoh: 001/RS/IT/I/2026">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Nama Dokumen</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="data[${colCount}][nama_dokumen]"
|
||||||
|
placeholder="Contoh: Panduan Mencuci Tangan">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Tanggal Terbit</label>
|
||||||
|
<input class="form-control"
|
||||||
|
type="date"
|
||||||
|
name="data[${colCount}][date_active]">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input toggle-expired"
|
||||||
|
type="checkbox"
|
||||||
|
id="hasExpired_${colCount}"
|
||||||
|
data-target="expiredField_${colCount}">
|
||||||
|
<label class="form-check-label" for="hasExpired_${colCount}">Masa Berlaku Dokumen??</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-5" id="expiredField_${colCount}">
|
||||||
|
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||||||
|
<input class="form-control"
|
||||||
|
type="date"
|
||||||
|
name="data[${colCount}][tgl_expired]" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-5">
|
||||||
|
<label class="form-label fw-semibold">Boleh dilihat unit lain? <span class="text-danger">*</span></label>
|
||||||
|
<div class="border rounded-3 p-2 bg-light">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input"
|
||||||
|
type="radio"
|
||||||
|
name="data[${colCount}][is_permission]"
|
||||||
|
id="perm_yes_${colCount}"
|
||||||
|
value="1"
|
||||||
|
required>
|
||||||
|
<label class="form-check-label" for="perm_yes_${colCount}">Iya</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mt-1">
|
||||||
|
<input class="form-check-input"
|
||||||
|
type="radio"
|
||||||
|
name="data[${colCount}][is_permission]"
|
||||||
|
id="perm_no_${colCount}"
|
||||||
|
value="2"
|
||||||
|
required>
|
||||||
|
<label class="form-check-label" for="perm_no_${colCount}">Tidak</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label for="fileUpload_${colCount}" class="form-label fw-semibold">📂 Upload Dokumen (PDF)</label>
|
||||||
|
<div class="border rounded-3 p-3 bg-white shadow-sm">
|
||||||
|
<input class="form-control"
|
||||||
|
type="file"
|
||||||
|
id="fileUpload_${colCount}"
|
||||||
|
accept=".pdf"
|
||||||
|
name="data[${colCount}][file]">
|
||||||
|
<div class="mt-2 text-success fw-semibold d-none file-name" id="fileName_${colCount}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-text text-muted">Format yang didukung: <b>PDF</b>.</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
col.insertAdjacentHTML('beforeend', html);
|
||||||
|
selectOptionUnitKerjaV1(colCount);
|
||||||
|
colCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.removeCol = function(count){
|
||||||
|
const el = document.getElementById(`col-${count}`);
|
||||||
|
if (el) el.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formCreate) {
|
||||||
|
const select0 = $('#select_id_unit_kerja_0');
|
||||||
|
if (select0.length) selectOptionUnitKerjaV1(0);
|
||||||
|
|
||||||
|
formCreate.addEventListener('submit', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const submitBtn = formCreate.querySelector('button[type="submit"]');
|
||||||
|
if (submitBtn) submitBtn.disabled = true;
|
||||||
|
if (submitBtn) submitBtn.textContent = 'menyimpan...';
|
||||||
|
const formData = new FormData(formCreate);
|
||||||
|
|
||||||
|
fetch(`/uploadv2`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]')?.value || ''
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
}).then(async(res) => {
|
||||||
|
const responseData = await res.json();
|
||||||
|
if(responseData.status){
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Berhasil',
|
||||||
|
text: responseData.message || 'Data berhasil disimpan.',
|
||||||
|
timer: 1500,
|
||||||
|
showConfirmButton: false
|
||||||
|
});
|
||||||
|
const modalInstance = bootstrap.Modal.getInstance(modalCreate);
|
||||||
|
modalInstance?.hide();
|
||||||
|
resetCreateForm();
|
||||||
|
fetchData();
|
||||||
|
if(responseData.status_action === null || responseData.status_action === undefined){
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'info',
|
||||||
|
title: 'Perlu Persetujuan',
|
||||||
|
text: 'Dokumen yang Anda upload butuh persetujuan dari atasan.',
|
||||||
|
confirmButtonText: 'Tutup'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.');
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Gagal',
|
||||||
|
text: err.message || 'Terjadi kesalahan.'
|
||||||
|
});
|
||||||
|
}).finally(() => {
|
||||||
|
if (submitBtn) submitBtn.disabled = false;
|
||||||
|
if (submitBtn) submitBtn.textContent = 'Simpan';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
document.addEventListener('click', function(e){
|
document.addEventListener('click', function(e){
|
||||||
if(e.target.matches('.file-link')){
|
if(e.target.matches('.file-link')){
|
||||||
|
|||||||
@ -114,7 +114,7 @@
|
|||||||
|
|
||||||
<div class="col-md-6 d-flex justify-content-md-end">
|
<div class="col-md-6 d-flex justify-content-md-end">
|
||||||
<button type="button" class="btn btn-success w-100 w-md-auto" data-bs-target="#modalCreateFile" data-bs-toggle="modal">
|
<button type="button" class="btn btn-success w-100 w-md-auto" data-bs-target="#modalCreateFile" data-bs-toggle="modal">
|
||||||
<i class="fa fa-plus me-1"></i> Tambah File
|
<i class="fa fa-plus me-1"></i> Tambah Dokumen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
0 dipilih
|
0 dipilih
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- TAMBAH FILE -->
|
<!-- Tambah Dokumen -->
|
||||||
{{-- <button
|
{{-- <button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-success btn-sm"
|
class="btn btn-success btn-sm"
|
||||||
@ -81,7 +81,7 @@
|
|||||||
data-bs-target="#modalCreateFile"
|
data-bs-target="#modalCreateFile"
|
||||||
>
|
>
|
||||||
<i class="ti ti-plus me-1"></i>
|
<i class="ti ti-plus me-1"></i>
|
||||||
Tambah File
|
Tambah Dokumen
|
||||||
</button> --}}
|
</button> --}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -500,9 +500,7 @@
|
|||||||
return d.toLocaleDateString('id-ID', {
|
return d.toLocaleDateString('id-ID', {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
year: 'numeric',
|
year: 'numeric'
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fetchData()
|
fetchData()
|
||||||
@ -600,37 +598,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('click', function (e) {
|
|
||||||
const btn = e.target.closest('.folder-prefill');
|
|
||||||
if (!btn) return;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
unitId: btn.getAttribute('data-unit_id') || '',
|
|
||||||
subId: btn.getAttribute('data-sub_id') || '',
|
|
||||||
kategoriId: btn.getAttribute('data-kategori_id') || '',
|
|
||||||
unitName: btn.getAttribute('data-unit_name') || '',
|
|
||||||
subName: btn.getAttribute('data-sub_name') || '',
|
|
||||||
kategoriName: btn.getAttribute('data-kategori_name') || '',
|
|
||||||
};
|
|
||||||
|
|
||||||
fetch('/dashboard/prefill', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
|
||||||
'X-Requested-With': 'XMLHttpRequest'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
if (!res.ok) throw new Error('Gagal set filter');
|
|
||||||
window.location.href = '/';
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
Swal.fire({ icon: 'error', title: 'Gagal', text: 'Tidak bisa buka folder' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let colCount = 1;
|
let colCount = 1;
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
@ -796,7 +764,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 d-none" id="expiredField_${colCount}">
|
<div class="col-md-5 d-none" id="expiredField_${colCount}">
|
||||||
<label class="form-label fw-semibold">Tanggal Expired</label>
|
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||||||
<input class="form-control" type="date" name="data[${colCount}][tgl_expired]">
|
<input class="form-control" type="date" name="data[${colCount}][tgl_expired]">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 d-none" id="expiredField_0">
|
<div class="col-md-5 d-none" id="expiredField_0">
|
||||||
<label class="form-label fw-semibold">Tanggal Expired</label>
|
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||||||
<input class="form-control" type="date" name="data[0][tgl_expired]">
|
<input class="form-control" type="date" name="data[0][tgl_expired]">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -71,7 +71,7 @@
|
|||||||
0 dipilih
|
0 dipilih
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- TAMBAH FILE -->
|
<!-- Tambah Dokumen -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-success btn-sm"
|
class="btn btn-success btn-sm"
|
||||||
@ -79,7 +79,7 @@
|
|||||||
data-bs-target="#modalCreateFile"
|
data-bs-target="#modalCreateFile"
|
||||||
>
|
>
|
||||||
<i class="ti ti-plus me-1"></i>
|
<i class="ti ti-plus me-1"></i>
|
||||||
Tambah File
|
Tambah Dokumen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -183,14 +183,8 @@
|
|||||||
const targetId = e.target.getAttribute('data-target');
|
const targetId = e.target.getAttribute('data-target');
|
||||||
if(!targetId) return;
|
if(!targetId) return;
|
||||||
const fieldWrap = document.getElementById(targetId);
|
const fieldWrap = document.getElementById(targetId);
|
||||||
if(!fieldWrap) return;
|
const input = fieldWrap.querySelector('input');
|
||||||
if(e.target.checked){
|
input.disabled = !e.target.checked;
|
||||||
fieldWrap.classList.remove('d-none');
|
|
||||||
}else{
|
|
||||||
fieldWrap.classList.add('d-none');
|
|
||||||
const input = fieldWrap.querySelector('input[type="date"]');
|
|
||||||
if(input) input.value = '';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if(pageSizeSelect){
|
if(pageSizeSelect){
|
||||||
@ -487,13 +481,10 @@
|
|||||||
|
|
||||||
function formatTanggal(dateString) {
|
function formatTanggal(dateString) {
|
||||||
const d = new Date(dateString);
|
const d = new Date(dateString);
|
||||||
|
|
||||||
return d.toLocaleDateString('id-ID', {
|
return d.toLocaleDateString('id-ID', {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
year: 'numeric',
|
year: 'numeric'
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fetchData()
|
fetchData()
|
||||||
@ -591,37 +582,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('click', function (e) {
|
|
||||||
const btn = e.target.closest('.folder-prefill');
|
|
||||||
if (!btn) return;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
unitId: btn.getAttribute('data-unit_id') || '',
|
|
||||||
subId: btn.getAttribute('data-sub_id') || '',
|
|
||||||
kategoriId: btn.getAttribute('data-kategori_id') || '',
|
|
||||||
unitName: btn.getAttribute('data-unit_name') || '',
|
|
||||||
subName: btn.getAttribute('data-sub_name') || '',
|
|
||||||
kategoriName: btn.getAttribute('data-kategori_name') || '',
|
|
||||||
};
|
|
||||||
|
|
||||||
fetch('/dashboard/prefill', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
|
||||||
'X-Requested-With': 'XMLHttpRequest'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
if (!res.ok) throw new Error('Gagal set filter');
|
|
||||||
window.location.href = '/';
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
Swal.fire({ icon: 'error', title: 'Gagal', text: 'Tidak bisa buka folder' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let colCount = 1;
|
let colCount = 1;
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
@ -661,12 +622,6 @@
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
});
|
});
|
||||||
|
|
||||||
// // --- isi default unit kerja ---
|
|
||||||
// if(authUnitKerja){
|
|
||||||
// let option = new Option(authUnitKerja.name, authUnitKerja.id, true, true);
|
|
||||||
// $('.unit_kerja').append(option).trigger('change');
|
|
||||||
// }
|
|
||||||
|
|
||||||
let initialUnit = $('.unit_kerja').val();
|
let initialUnit = $('.unit_kerja').val();
|
||||||
if(initialUnit){
|
if(initialUnit){
|
||||||
loadSubUnitKerja(initialUnit);
|
loadSubUnitKerja(initialUnit);
|
||||||
@ -778,21 +733,21 @@
|
|||||||
type="date"
|
type="date"
|
||||||
name="data[${colCount}][date_active]">
|
name="data[${colCount}][date_active]">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2 d-flex align-items-end">
|
<div class="col-md-2">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input toggle-expired"
|
<input class="form-check-input toggle-expired"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="hasExpired_${colCount}"
|
id="hasExpired_${colCount}"
|
||||||
data-target="expiredField_${colCount}">
|
data-target="expiredField_${colCount}">
|
||||||
<label class="form-check-label" for="hasExpired_${colCount}">Ada Expired?</label>
|
<label class="form-check-label" for="hasExpired_${colCount}">Masa Berlaku Dokumen??</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-5" id="expiredField_${colCount}">
|
<div class="col-md-5" id="expiredField_${colCount}">
|
||||||
<label class="form-label fw-semibold">Tanggal Expired</label>
|
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||||||
<input class="form-control"
|
<input class="form-control"
|
||||||
type="date"
|
type="date"
|
||||||
name="data[${colCount}][tgl_expired]">
|
name="data[${colCount}][tgl_expired]" disabled>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
@ -946,7 +901,7 @@
|
|||||||
const deleteWrapper = document.getElementById('deleteData');
|
const deleteWrapper = document.getElementById('deleteData');
|
||||||
|
|
||||||
if (Number(pegawai_id_entry) === Number(authPegawai)) {
|
if (Number(pegawai_id_entry) === Number(authPegawai)) {
|
||||||
deleteWrapper.classList.remove('d-none');
|
deleteWrapper.remove('d-none');
|
||||||
} else {
|
} else {
|
||||||
deleteWrapper.classList.add('d-none');
|
deleteWrapper.classList.add('d-none');
|
||||||
}
|
}
|
||||||
@ -961,14 +916,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(e.target.id === 'delete-file'){
|
if(e.target.id === 'delete-file'){
|
||||||
if(!currentFile){
|
|
||||||
Swal.fire({
|
|
||||||
text: "Tidak ada file yang dipilih!",
|
|
||||||
icon: "warning",
|
|
||||||
confirmButtonText: "OK"
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Yakin ingin menghapus file ini?',
|
title: 'Yakin ingin menghapus file ini?',
|
||||||
text: "File akan dihapus",
|
text: "File akan dihapus",
|
||||||
|
|||||||
@ -57,16 +57,15 @@
|
|||||||
<label class="form-label fw-semibold">Tanggal Terbit</label>
|
<label class="form-label fw-semibold">Tanggal Terbit</label>
|
||||||
<input class="form-control" type="date" name="data[0][date_active]">
|
<input class="form-control" type="date" name="data[0][date_active]">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2 d-flex align-items-end">
|
<div class="col-md-2">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input toggle-expired" type="checkbox" id="hasExpired0" data-target="expiredField_0">
|
<input class="form-check-input toggle-expired" type="checkbox" id="hasExpired0" data-target="expiredField_0">
|
||||||
<label class="form-check-label" for="hasExpired0">Ada Expired?</label>
|
<label class="form-check-label" for="hasExpired0">Masa Berlaku Dokumen?</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5" id="expiredField_0">
|
<div class="col-md-5" id="expiredField_0">
|
||||||
<label class="form-label fw-semibold">Tanggal Expired</label>
|
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||||||
<input class="form-control" type="date" name="data[0][tgl_expired]">
|
<input class="form-control" type="date" name="data[0][tgl_expired]" disabled>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<label class="form-label fw-semibold">Boleh dilihat unit lain? <span class="text-danger">*</span></label>
|
<label class="form-label fw-semibold">Boleh dilihat unit lain? <span class="text-danger">*</span></label>
|
||||||
|
|||||||
@ -45,15 +45,7 @@
|
|||||||
{{-- AKTIVITAS --}}
|
{{-- AKTIVITAS --}}
|
||||||
<li class="nav-small-cap"><span class="hide-menu">Aktivitas</span></li>
|
<li class="nav-small-cap"><span class="hide-menu">Aktivitas</span></li>
|
||||||
|
|
||||||
<li class="sidebar-item">
|
|
||||||
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
|
||||||
href="{{ url('/log-activity') }}" aria-expanded="false">
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<i class="ti ti-activity"></i>
|
|
||||||
<span class="hide-menu">Log Aktivitas</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@php
|
@php
|
||||||
$isAtasan = \App\Models\MappingUnitKerjaPegawai::where('statusenabled', true)->where('objectatasanlangsungfk', auth()->user()->objectpegawaifk)->exists();
|
$isAtasan = \App\Models\MappingUnitKerjaPegawai::where('statusenabled', true)->where('objectatasanlangsungfk', auth()->user()->objectpegawaifk)->exists();
|
||||||
@endphp
|
@endphp
|
||||||
@ -82,6 +74,15 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
<li class="sidebar-item">
|
||||||
|
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
||||||
|
href="{{ url('/log-activity') }}" aria-expanded="false">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<i class="ti ti-activity"></i>
|
||||||
|
<span class="hide-menu">Log Aktivitas</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{{-- RECAP --}}
|
{{-- RECAP --}}
|
||||||
{{-- <li class="nav-small-cap"><span class="hide-menu">Recap</span></li>
|
{{-- <li class="nav-small-cap"><span class="hide-menu">Recap</span></li>
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<input type="search"
|
<input type="search"
|
||||||
id="tableSearch"
|
id="tableSearch"
|
||||||
class="form-control border-start-0"
|
class="form-control border-start-0"
|
||||||
placeholder="Cari nama file / nomor dokumen / aksi"
|
placeholder="Cari nama dokumen / nomor dokumen / aksi"
|
||||||
oninput="debouncedTableSearch(this.value)">
|
oninput="debouncedTableSearch(this.value)">
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>No Dokumen</th>
|
<th>No Dokumen</th>
|
||||||
<th>File</th>
|
<th>Nama Dokumen</th>
|
||||||
<th>Kategori</th>
|
<th>Kategori</th>
|
||||||
<th>Unit</th>
|
<th>Unit</th>
|
||||||
<th>Pengunggah</th>
|
<th>Pengunggah</th>
|
||||||
|
|||||||
@ -1,54 +1,21 @@
|
|||||||
@extends('layout.main')
|
@extends('layout.main')
|
||||||
@section('body_main')
|
@section('body_main')
|
||||||
<style>
|
|
||||||
.pending-table thead th {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 2;
|
|
||||||
background: #f8f9fa;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.pending-table th,
|
|
||||||
.pending-table td {
|
|
||||||
padding-top: 0.6rem;
|
|
||||||
padding-bottom: 0.6rem;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
.pending-table .col-select {
|
|
||||||
width: 36px;
|
|
||||||
}
|
|
||||||
.pending-table .col-actions {
|
|
||||||
width: 92px;
|
|
||||||
}
|
|
||||||
.pending-table .cell-wrap {
|
|
||||||
line-height: 1.25;
|
|
||||||
white-space: normal;
|
|
||||||
word-break: break-word;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.pending-table .doc-title {
|
|
||||||
max-width: 260px;
|
|
||||||
display: inline-block;
|
|
||||||
white-space: normal;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.pending-table .col-kategori {
|
|
||||||
max-width: 180px;
|
|
||||||
}
|
|
||||||
.pending-table .col-unit {
|
|
||||||
max-width: 200px;
|
|
||||||
}
|
|
||||||
.pending-table .col-uploader {
|
|
||||||
max-width: 160px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header d-flex align-items-center justify-content-between">
|
<div class="card-header d-flex align-items-center justify-content-between">
|
||||||
<h4 class="mb-0">Data Pending</h4>
|
<h4 class="mb-0" id="pendingTitle">Data Pending</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-3">
|
<div class="card-body p-3">
|
||||||
|
<ul class="nav nav-tabs mb-3" id="pengajuanTabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<button class="nav-link active" type="button" data-mode="pengajuan">Data Pending</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<button class="nav-link" type="button" data-mode="history">Log History</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 mb-3 flex-wrap">
|
<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;">
|
<div class="input-group input-group-sm flex-grow-1" style="max-width:320px;">
|
||||||
<span class="input-group-text bg-white border-end-0">
|
<span class="input-group-text bg-white border-end-0">
|
||||||
@ -77,7 +44,7 @@
|
|||||||
<option value="100">100</option>
|
<option value="100">100</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2" id="pendingBulkActions">
|
||||||
<button class="btn btn-success btn-sm" id="bulkApproveBtn" disabled>
|
<button class="btn btn-success btn-sm" id="bulkApproveBtn" disabled>
|
||||||
<i class="fa-solid fa-check"></i> Approve dipilih (<span id="selectedCount">0</span>)
|
<i class="fa-solid fa-check"></i> Approve dipilih (<span id="selectedCount">0</span>)
|
||||||
</button>
|
</button>
|
||||||
@ -90,32 +57,57 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
|
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
|
<div id="tabPengajuan">
|
||||||
<table class="table table-sm table-hover table-striped align-middle mb-0 pending-table" id="lastUpdatedTable">
|
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto; overflow-x:auto;">
|
||||||
<thead>
|
<table class="table table-sm table-hover table-striped align-middle mb-0 pending-table" id="lastUpdatedTable">
|
||||||
<tr>
|
<thead>
|
||||||
<th class="col-select text-center">
|
<tr>
|
||||||
<input type="checkbox" class="form-check-input" id="selectAllPending" title="Pilih semua di halaman">
|
<th class="col-select text-center">
|
||||||
</th>
|
<input type="checkbox" class="form-check-input" id="selectAllPending" title="Pilih semua di halaman">
|
||||||
<th class="col-actions text-center">Aksi</th>
|
</th>
|
||||||
<th>No. Dokumen</th>
|
<th class="col-actions text-center">Aksi</th>
|
||||||
<th>Status</th>
|
<th>No. Dokumen</th>
|
||||||
<th>Akses</th>
|
<th>Status</th>
|
||||||
<th>Nama</th>
|
<th>Akses</th>
|
||||||
<th class="col-kategori">Kategori</th>
|
<th>Nama</th>
|
||||||
<th class="col-unit">Unit / Sub Unit</th>
|
<th class="col-kategori">Kategori</th>
|
||||||
<th>Tanggal Terbit</th>
|
<th class="col-unit">Unit</th>
|
||||||
<th>Tanggal Expired</th>
|
<th>Tanggal Terbit</th>
|
||||||
<th>Tanggal Upload</th>
|
<th>Tanggal Kedaluwarsa Dokumen</th>
|
||||||
<th class="col-uploader">Pengunggah</th>
|
<th>Tanggal Upload</th>
|
||||||
</tr>
|
<th class="col-uploader">Pengunggah</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody id="tablePendingFile">
|
</thead>
|
||||||
<!-- data dari fetch masuk sini -->
|
<tbody id="tablePendingFile">
|
||||||
</tbody>
|
<!-- data dari fetch masuk sini -->
|
||||||
</table>
|
</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 id="tabHistory" class="d-none">
|
||||||
|
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto; overflow-x:auto;">
|
||||||
|
<table class="table table-sm table-hover align-middle mb-0" id="tableHistory">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>No Dokumen</th>
|
||||||
|
<th>Akses</th>
|
||||||
|
<th>Nama</th>
|
||||||
|
<th>Kategori</th>
|
||||||
|
<th>Unit</th>
|
||||||
|
<th>Aksi</th>
|
||||||
|
<th>Tanggal Terbit</th>
|
||||||
|
<th>Tanggal Kedaluwarsa Dokumen</th>
|
||||||
|
<th>Tanggal Upload</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tableHistoryFile">
|
||||||
|
<!-- 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="paginationHistory"></div>
|
||||||
</div>
|
</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>
|
||||||
|
|||||||
@ -1,12 +1,55 @@
|
|||||||
@extends('layout.main')
|
@extends('layout.main')
|
||||||
|
<style>
|
||||||
|
/* select2 readability like dataUnit */
|
||||||
|
.select2-container--default .select2-selection--multiple {
|
||||||
|
background: #fff !important;
|
||||||
|
border: 1px solid #ced4da !important;
|
||||||
|
min-height: 31px;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__rendered,
|
||||||
|
.select2-container--default .select2-search--inline .select2-search__field,
|
||||||
|
.select2-container--default .select2-results__option {
|
||||||
|
color: #111 !important;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-dropdown {
|
||||||
|
background: #fff !important;
|
||||||
|
border: 1px solid #ced4da !important;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
|
||||||
|
background: #e9ecef !important;
|
||||||
|
color: #111 !important;
|
||||||
|
}
|
||||||
|
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||||
|
background: #f1f3f5 !important;
|
||||||
|
border: 1px solid #dee2e6 !important;
|
||||||
|
color: #111 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@section('body_main')
|
@section('body_main')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header d-flex align-items-center justify-content-between">
|
<div class="card-header d-flex align-items-center justify-content-between">
|
||||||
<h4 class="mb-0">Data Pending</h4>
|
<h4 class="mb-0" id="pengajuanTitle">Data Pengajuan</h4>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-success btn-sm"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#modalCreateFile"
|
||||||
|
>
|
||||||
|
<i class="ti ti-plus me-1"></i>
|
||||||
|
Tambah Dokumen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-3">
|
<div class="card-body p-3">
|
||||||
|
<ul class="nav nav-tabs mb-3" id="pengajuanTabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<button class="nav-link active" type="button" data-mode="pengajuan">Data Pengajuan</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<button class="nav-link" type="button" data-mode="history">Log History</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 mb-3 flex-wrap">
|
<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;">
|
<div class="input-group input-group-sm flex-grow-1" style="max-width:320px;">
|
||||||
<span class="input-group-text bg-white border-end-0">
|
<span class="input-group-text bg-white border-end-0">
|
||||||
@ -15,7 +58,7 @@
|
|||||||
<input type="search"
|
<input type="search"
|
||||||
id="tableSearch"
|
id="tableSearch"
|
||||||
class="form-control border-start-0"
|
class="form-control border-start-0"
|
||||||
placeholder="Cari nama file / nomor dokumen"
|
placeholder="Cari nama dokumen / nomor dokumen"
|
||||||
oninput="debouncedTableSearch(this.value)">
|
oninput="debouncedTableSearch(this.value)">
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
@ -40,28 +83,53 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
|
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
|
<div id="tabPengajuan">
|
||||||
<table class="table table-sm table-hover align-middle mb-0" id="lastUpdatedTable">
|
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
|
||||||
<thead>
|
<table class="table table-sm table-hover align-middle mb-0" id="tablePengajuan">
|
||||||
<tr>
|
<thead>
|
||||||
<th>Aksi</th>
|
<tr>
|
||||||
<th>No Dokumen</th>
|
<th>Aksi</th>
|
||||||
<th>Status</th>
|
<th>No Dokumen</th>
|
||||||
<th>Akses</th>
|
<th>Status</th>
|
||||||
<th>Nama</th>
|
<th>Akses</th>
|
||||||
<th>Kategori</th>
|
<th>Nama</th>
|
||||||
<th>Unit</th>
|
<th>Kategori</th>
|
||||||
<th>Tanggal Terbit</th>
|
<th>Unit</th>
|
||||||
<th>Tanggal Expired</th>
|
<th>Tanggal Terbit</th>
|
||||||
<th>Tanggal Upload</th>
|
<th>Tanggal Kedaluwarsa Dokumen</th>
|
||||||
</tr>
|
<th>Tanggal Upload</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody id="tablePengajuanFile">
|
</thead>
|
||||||
<!-- data dari fetch masuk sini -->
|
<tbody id="tablePengajuanFile">
|
||||||
</tbody>
|
<!-- data dari fetch masuk sini -->
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2 mt-3" id="paginationPengajuan"></div>
|
||||||
|
</div>
|
||||||
|
<div id="tabHistory" class="d-none">
|
||||||
|
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
|
||||||
|
<table class="table table-sm table-hover align-middle mb-0" id="tableHistory">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>No Dokumen</th>
|
||||||
|
<th>Akses</th>
|
||||||
|
<th>Nama</th>
|
||||||
|
<th>Kategori</th>
|
||||||
|
<th>Unit</th>
|
||||||
|
<th>Aksi</th>
|
||||||
|
<th>Tanggal Terbit</th>
|
||||||
|
<th>Tanggal Kedaluwarsa Dokumen</th>
|
||||||
|
<th>Tanggal Upload</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tableHistoryFile">
|
||||||
|
<!-- 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="paginationHistory"></div>
|
||||||
</div>
|
</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>
|
||||||
@ -69,5 +137,9 @@
|
|||||||
</div>
|
</div>
|
||||||
@include('pendingFile.modal.view')
|
@include('pendingFile.modal.view')
|
||||||
@include('pengajuanFile.modal.edit')
|
@include('pengajuanFile.modal.edit')
|
||||||
|
@include('dataUnit.modal.create')
|
||||||
|
<script>
|
||||||
|
window.katDok = @json($katDok);
|
||||||
|
</script>
|
||||||
<script src="{{ ver('/js/pengajuanFile/index.js') }}"></script>
|
<script src="{{ ver('/js/pengajuanFile/index.js') }}"></script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
@ -61,9 +61,9 @@
|
|||||||
<label class="form-check-label" for="edit_has_expired">Ada Expired?</label>
|
<label class="form-check-label" for="edit_has_expired">Ada Expired?</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 d-none" id="edit_expired_field">
|
<div class="col-md-5" id="edit_expired_field">
|
||||||
<label class="form-label fw-semibold">Tanggal Expired</label>
|
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||||||
<input class="form-control" type="date" name="tgl_expired" id="edit_tgl_expired">
|
<input class="form-control" type="date" name="tgl_expired" id="edit_tgl_expired" disabled>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<label class="form-label fw-semibold">Boleh dilihat unit lain? <span class="text-danger">*</span></label>
|
<label class="form-label fw-semibold">Boleh dilihat unit lain? <span class="text-danger">*</span></label>
|
||||||
|
|||||||
@ -22,10 +22,10 @@ Route::middleware(['auth'])->group(function(){
|
|||||||
Route::get('/file-download/{id}', [DashboardController::class, 'downloadFile']);
|
Route::get('/file-download/{id}', [DashboardController::class, 'downloadFile']);
|
||||||
Route::get('/full-preview/{id}', [DashboardController::class, 'dataPdfV2']);
|
Route::get('/full-preview/{id}', [DashboardController::class, 'dataPdfV2']);
|
||||||
Route::post('/upload', [DashboardController::class, 'store']);
|
Route::post('/upload', [DashboardController::class, 'store']);
|
||||||
Route::get('/data-unit-kerja', [DashboardController::class, 'dataUnitKerja']);
|
// Route::get('/data-unit-kerja', [DashboardController::class, 'dataUnitKerja']);
|
||||||
Route::post('/dashboard/prefill', [DashboardController::class, 'setDashboardPrefill']);
|
// Route::post('/dashboard/prefill', [DashboardController::class, 'setDashboardPrefill']);
|
||||||
|
|
||||||
Route::get('/select-pegawai', [AksesFileController::class, 'optionPegawai']);
|
// Route::get('/select-pegawai', [AksesFileController::class, 'optionPegawai']);
|
||||||
Route::get('/select-unit-kerja-option', [AksesFileController::class, 'optionUnitKerja']);
|
Route::get('/select-unit-kerja-option', [AksesFileController::class, 'optionUnitKerja']);
|
||||||
Route::middleware(['akses.master'])->group(function () {
|
Route::middleware(['akses.master'])->group(function () {
|
||||||
Route::resource('/akses', AksesFileController::class);
|
Route::resource('/akses', AksesFileController::class);
|
||||||
@ -42,8 +42,10 @@ Route::middleware(['auth'])->group(function(){
|
|||||||
Route::get('/select-unit-kerja-mapping', [DashboardController::class, 'OptionUnitKerjaByMapping']);
|
Route::get('/select-unit-kerja-mapping', [DashboardController::class, 'OptionUnitKerjaByMapping']);
|
||||||
Route::get('/select-sub-unit-kerja/{id}', [DashboardController::class, 'optionSubUnitKerja']);
|
Route::get('/select-sub-unit-kerja/{id}', [DashboardController::class, 'optionSubUnitKerja']);
|
||||||
Route::get('/select-sub-unit-kerja-mapping/{id}', [DashboardController::class, 'optionSubUnitKerjaByMapping']);
|
Route::get('/select-sub-unit-kerja-mapping/{id}', [DashboardController::class, 'optionSubUnitKerjaByMapping']);
|
||||||
|
|
||||||
|
|
||||||
Route::delete('/delete-file/{id}', [DashboardController::class, 'deleteFile']);
|
Route::delete('/delete-file/{id}', [DashboardController::class, 'deleteFile']);
|
||||||
Route::get('/getFile/{id_unit_kerja}/{id_sub_unit_kerja}/{master_kategori_directory_id}', [DashboardController::class, 'getFile']);
|
// Route::get('/getFile/{id_unit_kerja}/{id_sub_unit_kerja}/{master_kategori_directory_id}', [DashboardController::class, 'getFile']);
|
||||||
|
|
||||||
Route::post('/download-multiple', [DashboardController::class, 'downloadDataMultiple']);
|
Route::post('/download-multiple', [DashboardController::class, 'downloadDataMultiple']);
|
||||||
Route::post('/download-byfolder', [DashboardController::class, 'downloadDataFolder']);
|
Route::post('/download-byfolder', [DashboardController::class, 'downloadDataFolder']);
|
||||||
@ -51,6 +53,7 @@ Route::middleware(['auth'])->group(function(){
|
|||||||
Route::get('/log-activity', [LogActivityController::class, 'index']);
|
Route::get('/log-activity', [LogActivityController::class, 'index']);
|
||||||
Route::get('/datatable/log-activity', [LogActivityController::class, 'datatable']);
|
Route::get('/datatable/log-activity', [LogActivityController::class, 'datatable']);
|
||||||
Route::get('/datatable/log-activity/{fileDirectoryId}', [LogActivityController::class, 'detailByFile']);
|
Route::get('/datatable/log-activity/{fileDirectoryId}', [LogActivityController::class, 'detailByFile']);
|
||||||
|
Route::get('/datatable/log-activity-pengajuan', [LogActivityController::class, 'datatableHistoryPengajuan']);
|
||||||
|
|
||||||
Route::get('/recap', [DashboardController::class, 'recapView']);
|
Route::get('/recap', [DashboardController::class, 'recapView']);
|
||||||
Route::get('/data/recap', [DashboardController::class, 'recapData']);
|
Route::get('/data/recap', [DashboardController::class, 'recapData']);
|
||||||
@ -71,6 +74,8 @@ Route::middleware(['auth'])->group(function(){
|
|||||||
// });
|
// });
|
||||||
Route::get('/data/notifications', [DashboardController::class, 'notifkasiList']);
|
Route::get('/data/notifications', [DashboardController::class, 'notifkasiList']);
|
||||||
Route::post('/data/notifications/read', [DashboardController::class, 'notifkasiMarkRead']);
|
Route::post('/data/notifications/read', [DashboardController::class, 'notifkasiMarkRead']);
|
||||||
|
|
||||||
|
Route::get('/data/log-dokumen', [DashboardController::class, 'logDokumen']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/login', [AuthController::class, 'index'])->name('login');
|
Route::get('/login', [AuthController::class, 'index'])->name('login');
|
||||||
|
|||||||