progress revisi
This commit is contained in:
parent
c750177fee
commit
a0be3a4c74
@ -628,7 +628,6 @@ class DashboardController extends Controller
|
||||
'pegawai_id_entry' => auth()->user()->dataUser->id ?? 1,
|
||||
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap ?? 'tes',
|
||||
];
|
||||
dd($payload);
|
||||
if($file){
|
||||
$imageName = $file->getClientOriginalName();
|
||||
$path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}/{$nama_klasifikasi}";
|
||||
@ -714,85 +713,138 @@ class DashboardController extends Controller
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function deleteFile(string $id){
|
||||
public function deleteFile(string $id)
|
||||
{
|
||||
DB::connection('dbDirectory')->beginTransaction();
|
||||
try {
|
||||
$mapping = MappingUnitKerjaPegawai::where('statusenabled', true)
|
||||
->where('objectpegawaifk', auth()->user()?->dataUser?->id)
|
||||
->first();
|
||||
$mapping = $this->getDeleteNotificationMapping();
|
||||
$data = FileDirectory::where('file_directory_id', $id)->first();
|
||||
if(!$data){
|
||||
|
||||
if (!$data) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'File tidak ditemukan'
|
||||
]);
|
||||
}
|
||||
$fileInfo = pathinfo($data->file);
|
||||
$newFileName = $fileInfo['filename'] . '_deleted.' . ($fileInfo['extension'] ?? '');
|
||||
$dirName = $fileInfo['dirname'] ?? '';
|
||||
$newPath = ($dirName && $dirName !== '.') ? ($dirName . '/' . $newFileName) : $newFileName;
|
||||
$disk = Storage::disk('s3');
|
||||
if ($disk->exists($data->file)) {
|
||||
// S3 tidak bisa rename langsung, jadi copy lalu delete
|
||||
$disk->copy($data->file, $newPath);
|
||||
$disk->delete($data->file);
|
||||
], 404);
|
||||
}
|
||||
|
||||
$data->update([
|
||||
'statusenabled' => false,
|
||||
'file' => $newPath
|
||||
]);
|
||||
$this->deleteFileRecord($data, $mapping);
|
||||
|
||||
$uploaderName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna';
|
||||
$docNumber = $data->no_dokumen ? 'nomor '. $data->no_dokumen : $data->nama_dokumen;
|
||||
$payloadNotification = [
|
||||
'created_at' => now(),
|
||||
'text_notifikasi' => "Dokumen {$docNumber} . dihapus oleh {$uploaderName}.",
|
||||
'url' => '/pending-file',
|
||||
'is_read' => false,
|
||||
'pegawai_id' => $mapping?->objectatasanlangsungfk,
|
||||
];
|
||||
|
||||
Notifkasi::create($payloadNotification);
|
||||
if($mapping->objectpejabatpenilaifk){
|
||||
$payloadNotification = [
|
||||
'created_at' => now(),
|
||||
'text_notifikasi' => "Dokumen {$docNumber}. dihapus oleh {$uploaderName}.",
|
||||
'url' => '/pending-file',
|
||||
'is_read' => false,
|
||||
'pegawai_id' => $mapping?->objectpejabatpenilaifk,
|
||||
];
|
||||
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->no_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();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Berhasil menghapus data'
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::connection('dbDirectory')->rollBack();
|
||||
return response()->json([
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Gagal menghapus data'
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteFiles(Request $request)
|
||||
{
|
||||
$ids = collect($request->input('ids', []))
|
||||
->filter(fn ($id) => filled($id))
|
||||
->map(fn ($id) => (string) $id)
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
if ($ids->isEmpty()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Tidak ada dokumen yang dipilih'
|
||||
], 422);
|
||||
}
|
||||
|
||||
DB::connection('dbDirectory')->beginTransaction();
|
||||
try {
|
||||
$mapping = $this->getDeleteNotificationMapping();
|
||||
$files = FileDirectory::whereIn('file_directory_id', $ids)->get()->keyBy('file_directory_id');
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$data = $files->get($id);
|
||||
if (!$data) {
|
||||
throw new \RuntimeException("File {$id} tidak ditemukan");
|
||||
}
|
||||
|
||||
$this->deleteFileRecord($data, $mapping);
|
||||
}
|
||||
|
||||
DB::connection('dbDirectory')->commit();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Berhasil menghapus ' . $ids->count() . ' dokumen'
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::connection('dbDirectory')->rollBack();
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Gagal menghapus dokumen'
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
private function getDeleteNotificationMapping(): ?MappingUnitKerjaPegawai
|
||||
{
|
||||
return MappingUnitKerjaPegawai::where('statusenabled', true)
|
||||
->where('objectpegawaifk', auth()->user()?->dataUser?->id)
|
||||
->first();
|
||||
}
|
||||
|
||||
private function deleteFileRecord(FileDirectory $data, ?MappingUnitKerjaPegawai $mapping): void
|
||||
{
|
||||
$fileInfo = pathinfo((string) $data->file);
|
||||
$extension = $fileInfo['extension'] ?? '';
|
||||
$newFileName = ($fileInfo['filename'] ?? 'dokumen') . '_deleted' . ($extension !== '' ? '.' . $extension : '');
|
||||
$dirName = $fileInfo['dirname'] ?? '';
|
||||
$newPath = ($dirName && $dirName !== '.') ? ($dirName . '/' . $newFileName) : $newFileName;
|
||||
$disk = Storage::disk('s3');
|
||||
|
||||
if ($disk->exists($data->file)) {
|
||||
$disk->copy($data->file, $newPath);
|
||||
$disk->delete($data->file);
|
||||
}
|
||||
|
||||
$data->update([
|
||||
'statusenabled' => false,
|
||||
'file' => $newPath
|
||||
]);
|
||||
|
||||
$uploaderName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna';
|
||||
$docNumber = $data->no_dokumen ? 'nomor ' . $data->no_dokumen : $data->nama_dokumen;
|
||||
$notifiedPegawaiIds = collect([
|
||||
$mapping?->objectatasanlangsungfk,
|
||||
$mapping?->objectpejabatpenilaifk,
|
||||
])->filter()->unique();
|
||||
|
||||
foreach ($notifiedPegawaiIds as $pegawaiId) {
|
||||
Notifkasi::create([
|
||||
'created_at' => now(),
|
||||
'text_notifikasi' => "Dokumen {$docNumber}. dihapus oleh {$uploaderName}.",
|
||||
'url' => '/pending-file',
|
||||
'is_read' => false,
|
||||
'pegawai_id' => $pegawaiId,
|
||||
]);
|
||||
}
|
||||
|
||||
LogActivity::create([
|
||||
'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->no_dokumen ?? null,
|
||||
'mod_change' => null,
|
||||
'id_unit_kerja' => $data->id_unit_kerja,
|
||||
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
|
||||
'action_type' => 'Menghapus Dokumen',
|
||||
]);
|
||||
}
|
||||
|
||||
public function optionSubUnitKerja(string $id){
|
||||
@ -969,68 +1021,76 @@ class DashboardController extends Controller
|
||||
|
||||
public function downloadFile(string $id)
|
||||
{
|
||||
$data = FileDirectory::where('file_directory_id', $id)
|
||||
try {
|
||||
$data = FileDirectory::where('file_directory_id', $id)
|
||||
->where('statusenabled', true)
|
||||
->first();
|
||||
if (!$data) {
|
||||
abort(404, 'File tidak ditemukan');
|
||||
}
|
||||
$disk = Storage::disk('s3');
|
||||
if (!$data->file || !$disk->exists($data->file)) {
|
||||
abort(404, 'File tidak ditemukan');
|
||||
}
|
||||
|
||||
$user = auth()->user()->dataUser;
|
||||
if($user){
|
||||
$mapping = MappingUnitKerjaPegawai::where('statusenabled', true)
|
||||
->where('objectpegawaifk', $user->id)->where('isprimary', true)
|
||||
->first();
|
||||
LogActivity::create([
|
||||
'file_directory_id' => $id,
|
||||
'pegawai_id_entry' => $user->id,
|
||||
'pegawai_nama_entry' => $user->namalengkap,
|
||||
'entry_at' => now(),
|
||||
'action_type' => 'Download Dokumen',
|
||||
'no_dokumen' => $data->no_dokumen,
|
||||
'file' => $data->file,
|
||||
'statusenabled' => true,
|
||||
'mod_change' => null,
|
||||
'id_unit_kerja' => $mapping ? $mapping->objectunitkerjapegawaifk : 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 = [];
|
||||
$fileToSend = $this->prepareFileWithWatermark($localPath, $tempFiles);
|
||||
$downloadName = basename($data->file);
|
||||
|
||||
$response = response()->download($fileToSend, $downloadName);
|
||||
$response->deleteFileAfterSend(true);
|
||||
$cleanup = array_merge($tempFiles, [$localPath]);
|
||||
$cleanup = array_values(array_unique(array_filter($cleanup)));
|
||||
// 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);
|
||||
}
|
||||
if (!$data) {
|
||||
abort(404, 'File tidak ditemukan');
|
||||
}
|
||||
$disk = Storage::disk('s3');
|
||||
if (!$data->file || !$disk->exists($data->file)) {
|
||||
abort(404, 'File tidak ditemukan');
|
||||
}
|
||||
});
|
||||
|
||||
return $response;
|
||||
$user = auth()->user()->dataUser;
|
||||
if($user){
|
||||
$mapping = MappingUnitKerjaPegawai::where('statusenabled', true)
|
||||
->where('objectpegawaifk', $user->id)->where('isprimary', true)
|
||||
->first();
|
||||
LogActivity::create([
|
||||
'file_directory_id' => $id,
|
||||
'pegawai_id_entry' => $user->id,
|
||||
'pegawai_nama_entry' => $user->namalengkap,
|
||||
'entry_at' => now(),
|
||||
'action_type' => 'Download Dokumen',
|
||||
'no_dokumen' => $data->no_dokumen,
|
||||
'file' => $data->file,
|
||||
'statusenabled' => true,
|
||||
'mod_change' => null,
|
||||
'id_unit_kerja' => $mapping ? $mapping->objectunitkerjapegawaifk : 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 = [];
|
||||
$fileToSend = $this->prepareFileWithWatermark($localPath, $tempFiles);
|
||||
$downloadName = basename($data->file);
|
||||
|
||||
$response = response()->download($fileToSend, $downloadName);
|
||||
$response->deleteFileAfterSend(true);
|
||||
$cleanup = array_merge($tempFiles, [$localPath]);
|
||||
$cleanup = array_values(array_unique(array_filter($cleanup)));
|
||||
// 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;
|
||||
} catch (\Throwable $th) {
|
||||
return back()->with([
|
||||
'status' => false,
|
||||
'message' => 'terdapat kesalahan coba lagi nanti'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function dataUmum(){
|
||||
@ -2002,6 +2062,76 @@ class DashboardController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function recommendDeleteFile(Request $request, string $id)
|
||||
{
|
||||
try {
|
||||
DB::connection('dbDirectory')->beginTransaction();
|
||||
$data = FileDirectory::where('file_directory_id', $id)
|
||||
->where('statusenabled', true)
|
||||
->first();
|
||||
|
||||
if (!$data) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Data tidak ditemukan'
|
||||
], 404);
|
||||
}
|
||||
|
||||
$note = trim((string) $request->input('note', ''));
|
||||
if ($note === '') {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Catatan rekomendasi wajib diisi'
|
||||
], 422);
|
||||
}
|
||||
|
||||
$actionName = auth()->user()?->dataUser?->namalengkap ?? 'Pengguna';
|
||||
$docNumber = $data->no_dokumen ? 'nomor ' . $data->no_dokumen : ($data->nama_dokumen ?? 'dokumen');
|
||||
|
||||
Notifkasi::create([
|
||||
'created_at' => now(),
|
||||
'text_notifikasi' => "Dokumen {$docNumber} direkomendasikan untuk dihapus oleh {$actionName}. Catatan: {$note}",
|
||||
'url' => '/pengajuan-file',
|
||||
'is_read' => false,
|
||||
'pegawai_id' => $data->pegawai_id_entry,
|
||||
]);
|
||||
|
||||
LogActivity::create([
|
||||
'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->no_dokumen ?? null,
|
||||
'id_unit_kerja' => $data->id_unit_kerja,
|
||||
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
|
||||
'action_type' => 'Rekomendasi Hapus Dokumen',
|
||||
]);
|
||||
|
||||
$data->update([
|
||||
'hapus_turt' => true,
|
||||
'note_hapus_turt' => $note,
|
||||
'turt_by' => auth()->user()->objectpegawaifk,
|
||||
'turt_at' => now()
|
||||
]);
|
||||
|
||||
DB::connection('dbDirectory')->commit();
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => 'Rekomendasi hapus berhasil dikirim'
|
||||
], 200);
|
||||
} catch (\Throwable $th) {
|
||||
DB::connection('dbDirectory')->rollBack();
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => $th->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function countDataPending(){
|
||||
try {
|
||||
$objectpegawaifk = MappingUnitKerjaPegawai::query()
|
||||
|
||||
@ -12,7 +12,6 @@ class EnsureMasterPersetujuan
|
||||
{
|
||||
$user = $request->user();
|
||||
$hasAccess = $user && $user->masterPersetujuan;
|
||||
|
||||
if (!$hasAccess) {
|
||||
abort(403, 'Tidak memiliki akses.');
|
||||
}
|
||||
|
||||
@ -11,9 +11,9 @@ class SubUnitKerja extends Model
|
||||
public $timestamps = false;
|
||||
protected $primaryKey = 'id';
|
||||
protected $guarded = ['id'];
|
||||
protected $with = ['fileDirectory'];
|
||||
// protected $with = ['fileDirectory'];
|
||||
|
||||
public function fileDirectory(){
|
||||
return $this->hasMany(FileDirectory::class, 'id_sub_unit_kerja', 'id')->where('statusenabled', true);
|
||||
}
|
||||
// public function fileDirectory(){
|
||||
// return $this->hasMany(FileDirectory::class, 'id_sub_unit_kerja', 'id')->where('statusenabled', true);
|
||||
// }
|
||||
}
|
||||
|
||||
@ -11,10 +11,10 @@ class UnitKerja extends Model
|
||||
public $timestamps = false;
|
||||
protected $primaryKey = 'id';
|
||||
protected $guarded = ['id'];
|
||||
protected $with = ['subUnitKerja'];
|
||||
// protected $with = ['subUnitKerja'];
|
||||
|
||||
public function subUnitKerja(){
|
||||
return $this->hasMany(SubUnitKerja::class, 'objectunitkerjapegawaifk', 'id')->where('statusenabled', true)->select('id', 'objectunitkerjapegawaifk', 'name');
|
||||
}
|
||||
// public function subUnitKerja(){
|
||||
// return $this->hasMany(SubUnitKerja::class, 'objectunitkerjapegawaifk', 'id')->where('statusenabled', true)->select('id', 'objectunitkerjapegawaifk', 'name');
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@ -13,6 +13,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const titleEl = document.getElementById('pengajuanTitle');
|
||||
const tabPengajuanEl = document.getElementById('tabPengajuan');
|
||||
const tabHistoryEl = document.getElementById('tabHistory');
|
||||
const selectAllCheckbox = document.getElementById('selectAllPengajuan');
|
||||
const bulkDeleteBtn = document.getElementById('bulkDeleteBtn');
|
||||
const clearSelectionBtn = document.getElementById('clearSelectionBtn');
|
||||
const selectedCountEl = document.getElementById('selectedCount');
|
||||
const bulkActionsEl = document.getElementById('pengajuanBulkActions');
|
||||
const deleteDataEl = document.getElementById('deleteData');
|
||||
const formCreate = document.getElementById('formFile');
|
||||
const modalCreate = document.getElementById('modalCreateFile');
|
||||
let colCount = 1;
|
||||
@ -20,6 +26,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const editForm = document.getElementById('formEditPengajuanFile');
|
||||
const editUnitSelect = $('#edit_id_unit_kerja');
|
||||
const editSubUnitSelect = $('#edit_id_sub_unit_kerja');
|
||||
const selectedIds = new Set();
|
||||
|
||||
if (pageSizeSelect) {
|
||||
const initialSize = parseInt(pageSizeSelect.value);
|
||||
@ -61,6 +68,41 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
function getSelectableIdsOnPage(){
|
||||
return (tableState.data || []).map((row) => String(row.file_directory_id));
|
||||
}
|
||||
|
||||
function updateSelectAllState(){
|
||||
if (!selectAllCheckbox) return;
|
||||
if (tableState.mode === 'history') {
|
||||
selectAllCheckbox.checked = false;
|
||||
selectAllCheckbox.indeterminate = false;
|
||||
selectAllCheckbox.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const pageIds = getSelectableIdsOnPage();
|
||||
if (pageIds.length === 0) {
|
||||
selectAllCheckbox.checked = false;
|
||||
selectAllCheckbox.indeterminate = false;
|
||||
selectAllCheckbox.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
selectAllCheckbox.disabled = false;
|
||||
const selectedOnPage = pageIds.filter((id) => selectedIds.has(id)).length;
|
||||
selectAllCheckbox.checked = selectedOnPage > 0 && selectedOnPage === pageIds.length;
|
||||
selectAllCheckbox.indeterminate = selectedOnPage > 0 && selectedOnPage < pageIds.length;
|
||||
}
|
||||
|
||||
function updateSelectionUI(){
|
||||
const count = selectedIds.size;
|
||||
if (selectedCountEl) selectedCountEl.textContent = String(count);
|
||||
if (bulkDeleteBtn) bulkDeleteBtn.disabled = count === 0 || tableState.mode === 'history';
|
||||
if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history';
|
||||
updateSelectAllState();
|
||||
}
|
||||
|
||||
function buildRow(item){
|
||||
let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||||
let tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||||
@ -69,6 +111,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const isRejected = item?.status_action === 'rejected';
|
||||
const showEdit = !isApproved;
|
||||
const showInfo = isRejected;
|
||||
const id = String(item.file_directory_id);
|
||||
const checked = selectedIds.has(id);
|
||||
const aksi = `
|
||||
<div class="d-flex gap-1">
|
||||
<button href="#" class="btn btn-sm btn-primary" onclick="infoDok(this)"
|
||||
@ -93,7 +137,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
</div>
|
||||
`;
|
||||
return `
|
||||
<tr>
|
||||
<tr class="${checked ? 'table-active' : ''}">
|
||||
<td class="text-center">
|
||||
<input type="checkbox"
|
||||
class="form-check-input row-select"
|
||||
data-id="${id}"
|
||||
${checked ? 'checked' : ''}>
|
||||
</td>
|
||||
<td>${aksi}</td>
|
||||
<td>${item.no_dokumen || '-'}</td>
|
||||
<td>
|
||||
@ -168,6 +218,41 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return (tableState.data || []).find((row) => String(row.file_directory_id) === String(id));
|
||||
}
|
||||
|
||||
function deleteDocuments(ids, successMessage){
|
||||
return fetch('/delete-file/bulk', {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken
|
||||
},
|
||||
body: JSON.stringify({ ids })
|
||||
}).then(async(res) => {
|
||||
const data = await res.json();
|
||||
if (!res.ok || !data?.success) {
|
||||
throw new Error(data?.message || 'Gagal menghapus dokumen.');
|
||||
}
|
||||
|
||||
ids.forEach((id) => selectedIds.delete(String(id)));
|
||||
if (window.idDirectory && ids.includes(String(window.idDirectory))) {
|
||||
window.idDirectory = null;
|
||||
window.currentFile = null;
|
||||
if (deleteDataEl) deleteDataEl.classList.add('d-none');
|
||||
const modalEl = document.getElementById('previewModal');
|
||||
const modalInstance = modalEl ? bootstrap.Modal.getInstance(modalEl) : null;
|
||||
modalInstance?.hide();
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: data.message || successMessage,
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
});
|
||||
fetchData();
|
||||
});
|
||||
}
|
||||
|
||||
function renderPagination(totalPages){
|
||||
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||||
const paginationEl = tableState.mode === 'history' ? paginationHistory : paginationPengajuan;
|
||||
@ -218,7 +303,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const activeState = isHistoryMode ? historyState : tableState;
|
||||
const pageData = activeState.data || [];
|
||||
const targetBody = isHistoryMode ? tbodyHistory : tbodyPengajuan;
|
||||
const colSpan = isHistoryMode ? 9 : 10;
|
||||
const colSpan = isHistoryMode ? 9 : 11;
|
||||
const rowBuilder = isHistoryMode ? buildHistoryRow : buildRow;
|
||||
if (pageData.length === 0) {
|
||||
targetBody.innerHTML = `
|
||||
@ -239,6 +324,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
renderPagination(activeState.lastPage || 1);
|
||||
updateSelectionUI();
|
||||
}
|
||||
|
||||
let searchDebounce;
|
||||
@ -264,6 +350,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
document.getElementById('tableSearch').value = '';
|
||||
startDateInput.value = '';
|
||||
endDateInput.value = '';
|
||||
selectedIds.clear();
|
||||
tableState.page = 1;
|
||||
historyState.page = 1;
|
||||
fetchData();
|
||||
@ -278,10 +365,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (titleEl) {
|
||||
titleEl.textContent = tableState.mode === 'history' ? 'Log History' : 'Data Pengajuan';
|
||||
}
|
||||
document.body.dataset.pengajuanMode = tableState.mode;
|
||||
if (tabPengajuanEl && tabHistoryEl) {
|
||||
tabPengajuanEl.classList.toggle('d-none', tableState.mode === 'history');
|
||||
tabHistoryEl.classList.toggle('d-none', tableState.mode !== 'history');
|
||||
}
|
||||
if (bulkActionsEl) {
|
||||
bulkActionsEl.classList.toggle('d-none', tableState.mode === 'history');
|
||||
}
|
||||
if (deleteDataEl && tableState.mode === 'history') {
|
||||
deleteDataEl.classList.add('d-none');
|
||||
}
|
||||
updateSelectionUI();
|
||||
}
|
||||
|
||||
if (tabsEl) {
|
||||
@ -297,6 +392,63 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
if (tbodyPengajuan) {
|
||||
tbodyPengajuan.addEventListener('change', (e) => {
|
||||
const target = e.target;
|
||||
if (!target.classList.contains('row-select')) return;
|
||||
const id = target.getAttribute('data-id');
|
||||
if (!id) return;
|
||||
if (target.checked) selectedIds.add(id);
|
||||
else selectedIds.delete(id);
|
||||
const row = target.closest('tr');
|
||||
if (row) row.classList.toggle('table-active', target.checked);
|
||||
updateSelectionUI();
|
||||
});
|
||||
}
|
||||
|
||||
if (selectAllCheckbox) {
|
||||
selectAllCheckbox.addEventListener('change', () => {
|
||||
const pageIds = getSelectableIdsOnPage();
|
||||
if (selectAllCheckbox.checked) {
|
||||
pageIds.forEach((id) => selectedIds.add(id));
|
||||
} else {
|
||||
pageIds.forEach((id) => selectedIds.delete(id));
|
||||
}
|
||||
renderTable();
|
||||
});
|
||||
}
|
||||
|
||||
if (clearSelectionBtn) {
|
||||
clearSelectionBtn.addEventListener('click', () => {
|
||||
selectedIds.clear();
|
||||
renderTable();
|
||||
});
|
||||
}
|
||||
|
||||
if (bulkDeleteBtn) {
|
||||
bulkDeleteBtn.addEventListener('click', () => {
|
||||
if (selectedIds.size === 0) return;
|
||||
const ids = Array.from(selectedIds);
|
||||
Swal.fire({
|
||||
title: 'Hapus dokumen terpilih?',
|
||||
text: `Total ${ids.length} dokumen akan dihapus.`,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
deleteDocuments(ids, 'Dokumen berhasil dihapus.').catch((err) => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: err.message || 'Terjadi kesalahan.'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fetchData(){
|
||||
if (summaryEl) summaryEl.textContent = 'Memuat data...';
|
||||
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||||
@ -360,6 +512,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
permEl.textContent = publicDoc ? 'Umum' : 'Internal Unit';
|
||||
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
|
||||
}
|
||||
if (deleteDataEl) {
|
||||
deleteDataEl.classList.remove('d-none');
|
||||
}
|
||||
let previewBox = document.getElementById('file-preview');
|
||||
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
|
||||
<div id="pdfPages"></div>`;
|
||||
@ -1076,6 +1231,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
document.addEventListener('click', function(e){
|
||||
if(e.target.matches('.file-link')){
|
||||
@ -1105,6 +1261,10 @@ document.addEventListener('click', function(e){
|
||||
const publicDoc = isPublic(permissionFile);
|
||||
permEl.textContent = publicDoc ? 'Umum' : 'Internal Unit';
|
||||
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
|
||||
}
|
||||
const deleteDataEl = document.getElementById('deleteData');
|
||||
if (deleteDataEl) {
|
||||
deleteDataEl.classList.toggle('d-none', document.body.dataset.pengajuanMode !== 'pengajuan');
|
||||
}
|
||||
let previewBox = document.getElementById('file-preview');
|
||||
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
|
||||
@ -1119,6 +1279,56 @@ document.addEventListener('click', function(e){
|
||||
if(e.target.matches('#btn-view-full')){
|
||||
window.open(`/full-preview/${idDirectory}`, '_blank');
|
||||
}
|
||||
|
||||
if(e.target.matches('#delete-file')){
|
||||
if(!idDirectory){
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Pilih dokumen',
|
||||
text: 'Dokumen belum dipilih.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: 'Hapus dokumen ini?',
|
||||
text: 'Dokumen yang dihapus tidak akan tampil lagi.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
fetch('/delete-file/bulk', {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
|
||||
},
|
||||
body: JSON.stringify({ ids: [String(idDirectory)] })
|
||||
}).then(async(res) => {
|
||||
const data = await res.json();
|
||||
if (!res.ok || !data?.success) {
|
||||
throw new Error(data?.message || 'Gagal menghapus dokumen.');
|
||||
}
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: data.message || 'Dokumen berhasil dihapus.',
|
||||
timer: 1500,
|
||||
showConfirmButton: false
|
||||
}).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}).catch((err) => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: err.message || 'Terjadi kesalahan.'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
function isPublic(permissionVal){
|
||||
if(permissionVal === null || permissionVal === undefined) return false;
|
||||
|
||||
@ -226,7 +226,8 @@
|
||||
<script>
|
||||
const katDok = @json($katDok);
|
||||
const authUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->unitKerja);
|
||||
const authSubUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]->sub_unit_kerja);
|
||||
|
||||
// const authSubUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]->sub_unit_kerja);
|
||||
const mappingUnitKerjaPegawai = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]);
|
||||
const authPegawai = @json(auth()->user()->objectpegawaifk);
|
||||
const formCreate = $("#formFile")
|
||||
@ -472,6 +473,22 @@
|
||||
>
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</a>
|
||||
${authUnitKerja.id === 22 ? `
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning btn-sm"
|
||||
onclick="rekomendasiDelete(this)"
|
||||
title="Rekomendasi Hapus"
|
||||
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 || '-'}"
|
||||
data-pegawai_id_entry="${item.pegawai_id_entry || '-'}"
|
||||
>
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@ -1176,5 +1193,67 @@
|
||||
}
|
||||
$("#previewModal").modal('show')
|
||||
}
|
||||
|
||||
function rekomendasiDelete(button){
|
||||
const id = $(button).data('id');
|
||||
const fileName = $(button).data('filename') || 'dokumen';
|
||||
const noDokumen = $(button).data('no_dokumen') || '-';
|
||||
|
||||
Swal.fire({
|
||||
title: 'Rekomendasi hapus dokumen?',
|
||||
text: `${fileName} (${noDokumen})`,
|
||||
icon: 'warning',
|
||||
input: 'textarea',
|
||||
inputLabel: 'Catatan rekomendasi',
|
||||
inputPlaceholder: 'Tulis alasan kenapa dokumen ini direkomendasikan untuk dihapus...',
|
||||
inputAttributes: {
|
||||
'aria-label': 'Catatan rekomendasi'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Kirim rekomendasi',
|
||||
cancelButtonText: 'Batal',
|
||||
preConfirm: (value) => {
|
||||
const note = (value || '').trim();
|
||||
if (!note) {
|
||||
Swal.showValidationMessage('Catatan rekomendasi wajib diisi.');
|
||||
}
|
||||
return note;
|
||||
}
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
fetch(`/recommend-delete-file/${id}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
body: JSON.stringify({
|
||||
note: result.value
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: data.message || 'Rekomendasi hapus berhasil dikirim.',
|
||||
timer: 1800,
|
||||
showConfirmButton: false
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Gagal mengirim rekomendasi hapus.');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: err.message || 'Terjadi kesalahan.'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@ -308,7 +308,7 @@
|
||||
cache: true
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
if (kategoriSelect) {
|
||||
$('#tableKategori').select2({
|
||||
@ -607,6 +607,23 @@
|
||||
>
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</a>
|
||||
${authUnitKerja.id === 22 ? `
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning btn-sm"
|
||||
onclick="rekomendasiDelete(this)"
|
||||
title="Rekomendasi Hapus"
|
||||
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 || '-'}"
|
||||
data-pegawai_id_entry="${item.pegawai_id_entry || '-'}"
|
||||
>
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-nowrap">${item.no_dokumen || '-'}</td>
|
||||
@ -1020,6 +1037,8 @@
|
||||
url: `/select-sub-unit-kerja-mapping/${unitId}`,
|
||||
method: 'GET',
|
||||
success: function(response) {
|
||||
console.log(response);
|
||||
|
||||
if (response?.data) {
|
||||
response.data.forEach(unit => {
|
||||
let selected = (authSubUnitKerja && unit.id === authSubUnitKerja.objectsubunitkerjapegawaifk);
|
||||
@ -1228,7 +1247,7 @@
|
||||
processResults: function(data){
|
||||
return {
|
||||
results : data?.data.map(item => ({
|
||||
id: item.id+'/'+item.name,
|
||||
id: item.id,
|
||||
text: item.name,
|
||||
sub_units: item.sub_unit_kerja // kirim ke front
|
||||
}))
|
||||
@ -1482,5 +1501,67 @@
|
||||
}
|
||||
$("#previewModal").modal('show')
|
||||
}
|
||||
|
||||
function rekomendasiDelete(button){
|
||||
const id = $(button).data('id');
|
||||
const fileName = $(button).data('filename') || 'dokumen';
|
||||
const noDokumen = $(button).data('no_dokumen') || '-';
|
||||
|
||||
Swal.fire({
|
||||
title: 'Rekomendasi hapus dokumen?',
|
||||
text: `${fileName} (${noDokumen})`,
|
||||
icon: 'warning',
|
||||
input: 'textarea',
|
||||
inputLabel: 'Catatan rekomendasi',
|
||||
inputPlaceholder: 'Tulis alasan kenapa dokumen ini direkomendasikan untuk dihapus...',
|
||||
inputAttributes: {
|
||||
'aria-label': 'Catatan rekomendasi'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Kirim rekomendasi',
|
||||
cancelButtonText: 'Batal',
|
||||
preConfirm: (value) => {
|
||||
const note = (value || '').trim();
|
||||
if (!note) {
|
||||
Swal.showValidationMessage('Catatan rekomendasi wajib diisi.');
|
||||
}
|
||||
return note;
|
||||
}
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
fetch(`/recommend-delete-file/${id}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
body: JSON.stringify({
|
||||
note: result.value
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: data.message || 'Rekomendasi hapus berhasil dikirim.',
|
||||
timer: 1800,
|
||||
showConfirmButton: false
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Gagal mengirim rekomendasi hapus.');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
text: err.message || 'Terjadi kesalahan.'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
</a>
|
||||
</li>
|
||||
@if(!Auth::guard('admin')->check())
|
||||
@if(auth()->user()->dataUser->mappingUnitKerjaPegawai()->where('objectunitkerjapegawaifk', 43)->exists())
|
||||
@if(auth()->user()->dataUser->mappingUnitKerjaPegawai()->whereIn('objectunitkerjapegawaifk', [43, 22])->exists())
|
||||
<li class="nav-small-cap"><span class="hide-menu">Master</span></li>
|
||||
|
||||
<li class="sidebar-item has-sub {{ $openMaster ? 'open' : '' }}">
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
|
||||
<!-- Body -->
|
||||
<div class="modal-body p-2" style="min-height:250px; max-height:70vh; overflow:auto;">
|
||||
<div class="d-flex justify-content-end align-items-center sticky-top bg-white z-10 d-none" id="deleteData">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger mb-2 me-2" id="delete-file">Hapus</button>
|
||||
</div>
|
||||
<div id="file-preview"
|
||||
class="text-center text-muted d-flex justify-content-center align-items-center"
|
||||
style="height:100%;">
|
||||
|
||||
@ -78,6 +78,14 @@
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2" id="pengajuanBulkActions">
|
||||
<button class="btn btn-danger btn-sm" id="bulkDeleteBtn" disabled>
|
||||
Hapus dipilih (<span id="selectedCount">0</span>)
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-sm" id="clearSelectionBtn" disabled>
|
||||
Reset pilihan
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary btn-sm" onclick="refreshLog()">
|
||||
<i class="fa fa-rotate"></i> Refresh
|
||||
</button>
|
||||
@ -88,6 +96,9 @@
|
||||
<table class="table table-sm table-hover align-middle mb-0" id="tablePengajuan">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<input type="checkbox" class="form-check-input" id="selectAllPengajuan" title="Pilih semua di halaman">
|
||||
</th>
|
||||
<th>Aksi</th>
|
||||
<th>No Dokumen</th>
|
||||
<th>Status</th>
|
||||
|
||||
@ -51,7 +51,9 @@ Route::middleware(['auth:admin,web'])->group(function(){
|
||||
Route::get('/select-sub-unit-kerja-mapping/{id}', [DashboardController::class, 'optionSubUnitKerjaByMapping']);
|
||||
|
||||
|
||||
Route::delete('/delete-file/bulk', [DashboardController::class, 'deleteFiles']);
|
||||
Route::delete('/delete-file/{id}', [DashboardController::class, 'deleteFile']);
|
||||
Route::post('/recommend-delete-file/{id}', [DashboardController::class, 'recommendDeleteFile']);
|
||||
// Route::get('/getFile/{id_unit_kerja}/{id_sub_unit_kerja}/{master_kategori_directory_id}', [DashboardController::class, 'getFile']);
|
||||
|
||||
Route::post('/download-multiple', [DashboardController::class, 'downloadDataMultiple']);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user