fix(memo): perbaikkan upload foto di memo, foto existing hilang ketika upload ulang

This commit is contained in:
majid
2025-03-21 09:55:43 +07:00
parent 850074ee7e
commit b6e71ac865
4 changed files with 268 additions and 162 deletions

View File

@@ -834,13 +834,13 @@ class PenilaiController extends Controller
} }
$cekLpj =$this->checkDataLpj($type, $statusLpj) // $cekLpj = $this->checkDataLpj($type, $statusLpj);
if ($permohonan->status_bayar === 'sudah_bayar' && $cekLpj) { // if ($permohonan->status_bayar === 'sudah_bayar' && $cekLpj) {
return response()->json([ // return response()->json([
'success' => false, // 'success' => false,
'message' => 'Harap mengisi LPJ terlebih dahulu', // 'message' => 'Harap mengisi LPJ terlebih dahulu',
]) // ]);
} // }
$permohonan->update([ $permohonan->update([
@@ -862,14 +862,69 @@ class PenilaiController extends Controller
public function uploadTempPhoto(Request $request) public function uploadTempPhoto(Request $request)
{ {
$validatedData = $request->validate([
'permohonan_id' => 'required|integer',
'dokument_id' => 'required|integer',
]);
$memo = Penilai::firstOrNew([
'permohonan_id' => $validatedData['permohonan_id'],
'dokument_id' => $validatedData['dokument_id'],
]);
$existingData = $memo->exists && $memo->memo ? json_decode($memo->memo, true) : [];
$existingData['foto'] = $existingData['foto'] ?? [];
if ($request->hasFile('file')) { if ($request->hasFile('file')) {
$file = $request->file('file');
$files = $request->file('file');
if (!is_array($files)) {
$files = [$files];
}
foreach ($files as $file) {
$filename = time() . '_' . $file->getClientOriginalName(); $filename = time() . '_' . $file->getClientOriginalName();
$path = $file->storeAs('temp_photos', $filename, 'public'); $path = $file->storeAs('temp_photos', $filename, 'public');
return response()->json(['success' => true, 'id' => $path]); $existingData['foto'][] = $path;
}
// Simpan data memo
$memo->memo = json_encode($existingData);
$memo->save();
return response()->json(['success' => true, 'data' => $existingData]);
}
return response()->json(['success' => false], 400);
} }
return response()->json(['success' => false], 400);
public function deleteTempPhoto(Request $request)
{
$validatedData = $request->validate([
'permohonan_id' => 'required|integer',
'dokument_id' => 'required|integer',
'path' => 'required|string',
]);
$memo = Penilai::firstOrNew([
'permohonan_id' => $validatedData['permohonan_id'],
'dokument_id' => $validatedData['dokument_id'],
]);
$fotoMemo = json_decode($memo->memo, true);
if (isset($fotoMemo['foto']) && is_array($fotoMemo['foto'])) {
$fotoMemo['foto'] = array_filter($fotoMemo['foto'], function ($photo) use ($validatedData) {
return basename($photo) !== basename($validatedData['path']);
});
$fotoMemo['foto'] = array_values($fotoMemo['foto']);
$memo->memo = json_encode($fotoMemo);
$memo->save();
return response()->json(['success' => true, 'message' => 'Foto berhasil dihapus']);
}
return response()->json(['success' => false, 'message' => 'Foto tidak ditemukan'], 400);
} }
public function storeResume(Request $request) public function storeResume(Request $request)
@@ -964,42 +1019,20 @@ class PenilaiController extends Controller
'memo' => 'required', 'memo' => 'required',
]); ]);
$memoData = json_decode($validatedData['memo'], true); $newMemoData = json_decode($validatedData['memo'], true);
$memo = Penilai::updateOrCreate( $memo = Penilai::firstOrNew(
[ [
'permohonan_id' => $validatedData['permohonan_id'], 'permohonan_id' => $validatedData['permohonan_id'],
'dokument_id' => $validatedData['document_id'], 'dokument_id' => $validatedData['document_id'],
],
[
'memo' => json_encode($memoData),
] ]
); );
// $existingPhotos = isset($memo->memo) ? json_decode($memo->memo) : []; $existingMemoData = isset($memo->memo) ? json_decode($memo->memo, true) : [];
// dd($existingPhotos); $mergedMemoData = array_merge($existingMemoData, $newMemoData);
// Simpan foto-foto
if ($request->hasFile('foto_0')) {
$photoUrls = [];
$index = 0;
while ($request->hasFile("foto_$index")) {
$file = $request->file("foto_$index");
$fileName = time() . '_' . $file->getClientOriginalName();
$filePath = $file->storeAs('public/memo_photos', $fileName);
$photoUrls[] = Storage::url($filePath);
$index++;
}
// $memoData['foto'] = array_merge($existingPhotos, $photoUrls); $memo->memo = json_encode($mergedMemoData);
// }else{
// $memoData['foto'] = $existingPhotos;
// Tambahkan URL foto ke data memo
$memoData['foto'] = $photoUrls;
$memo->memo = json_encode($memoData);
$memo->save(); $memo->save();
}
return response()->json([ return response()->json([
'success' => true, 'success' => true,

View File

@@ -186,7 +186,8 @@
<div class="flex flex-wrap items-baseline w-full"> <div class="flex flex-wrap items-baseline w-full">
<input type="date-time" id="tanggal_survey" name="tanggal_survey" <input type="date-time" id="tanggal_survey" name="tanggal_survey"
class="input w-full" placeholder="Masukkan Tanggal Survey" class="input w-full" placeholder="Masukkan Tanggal Survey"
value="{{ $permohonan->penilaian->updated_at ?? old('tanggal_survey') }}" @readonly(true)> value="{{ $permohonan->penilaian->updated_at ?? old('tanggal_survey') }}"
@readonly(true)>
</div> </div>
</div> </div>
@@ -315,7 +316,8 @@
<div class="flex card-footer justify-end gap-5"> <div class="flex card-footer justify-end gap-5">
@if (Auth::user()->hasAnyRole(['senior-officer', 'surveyor', 'administrator'])) @if (Auth::user()->hasAnyRole(['senior-officer', 'surveyor', 'administrator']))
<a class="btn btn-primary" onclick="saveMemo()" {{ $permohonan->status == 'proses-paparan' || $permohonan->status == 'proses-laporan' && Auth::user()->hasAnyRole(['surveyor']) ? 'disabled' : '' }}> <a class="btn btn-primary" onclick="saveMemo()"
{{ $permohonan->status == 'proses-paparan' || ($permohonan->status == 'proses-laporan' && Auth::user()->hasAnyRole(['surveyor'])) ? 'disabled' : '' }}>
<i class="ki-filled ki-save-2"></i> <i class="ki-filled ki-save-2"></i>
Simpan Simpan
</a> </a>
@@ -347,11 +349,13 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
myDropzone = new Dropzone("#dropzone-upload", { myDropzone = new Dropzone("#dropzone-upload", {
url: "{{ route('penilai.uploadTempPhoto') }}", // Temporary upload route url: "{{ route('penilai.uploadTempPhoto') }}?permohonan_id={{ $permohonan->id }}&dokument_id={{ request('documentId') }}", // Temporary upload route
paramName: "file", paramName: "file",
maxFilesize: 5, // MB maxFilesize: 5, // MB
acceptedFiles: "image/*", acceptedFiles: "image/*",
addRemoveLinks: true, uploadMultiple: false,
parallelUploads: 1,
autoProcessQueue: true,
headers: { headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}' 'X-CSRF-TOKEN': '{{ csrf_token() }}'
}, },
@@ -380,21 +384,34 @@
} }
if (Array.isArray(existingPhotos)) { if (Array.isArray(existingPhotos)) {
const BASE_URL = "{{ asset('storage/') }}";
existingPhotos.forEach(function(photoPath) { existingPhotos.forEach(function(photoPath) {
if (typeof photoPath === 'string') { if (typeof photoPath === 'string') {
const photoDiv = document.createElement('div'); const photoDiv = document.createElement('div');
photoDiv.className = 'col-md-3 mb-3'; photoDiv.className = 'col-md-3 mb-3';
const img = document.createElement('img'); const img = document.createElement('img');
img.src = photoPath; img.src = BASE_URL + '/' + photoPath;
img.className = 'img-fluid'; img.className = 'img-fluid';
img.style.maxHeight = '150px'; img.style.maxHeight = '150px';
const deleteButton = document.createElement('button');
deleteButton.className = 'btn btn-danger btn-sm mt-2';
deleteButton.textContent = 'Hapus';
deleteButton.type = 'button';
deleteButton.onclick = function() {
handleDeletePhoto(photoPath, photoDiv);
};
photoDiv.appendChild(img); photoDiv.appendChild(img);
photoDiv.appendChild(deleteButton);
existingPhotosContainer.appendChild(photoDiv); existingPhotosContainer.appendChild(photoDiv);
if (myDropzone) { if (myDropzone) {
let mockFile = { name: photoPath.split('/').pop(), size: 12345 }; let mockFile = {
name: photoPath.split('/').pop(),
size: 12345
};
myDropzone.emit("addedfile", mockFile); myDropzone.emit("addedfile", mockFile);
myDropzone.emit("thumbnail", mockFile, photoPath); myDropzone.emit("thumbnail", mockFile, photoPath);
myDropzone.emit("complete", mockFile); myDropzone.emit("complete", mockFile);
@@ -409,6 +426,41 @@
@endif @endif
} }
function handleDeletePhoto(photoPath, photoDiv) {
const BASE_URL = "{{ asset('storage/') }}";
Swal.fire({
title: 'Hapus Foto?',
text: "Foto ini akan dihapus secara permanen!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ya, hapus!'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: "{{ route('penilai.deleteTempPhoto') }}",
method: 'DELETE',
data: {
path: photoPath,
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('documentId') ?? '' }}',
},
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function() {
Swal.fire('Dihapus!', 'Foto berhasil dihapus.', 'success');
photoDiv.remove();
},
error: function() {
Swal.fire('Gagal!', 'Foto gagal dihapus.', 'error');
}
})
}
});
}
function saveMemo() { function saveMemo() {
const form = document.getElementById('form-memo'); const form = document.getElementById('form-memo');
const formData = new FormData(form); const formData = new FormData(form);
@@ -447,11 +499,6 @@
sendFormData.append('document_id', documentId); sendFormData.append('document_id', documentId);
sendFormData.append('memo', JSON.stringify(jsonData)); sendFormData.append('memo', JSON.stringify(jsonData));
// Append all files from Dropzone
myDropzone.getAcceptedFiles().forEach((file, index) => {
sendFormData.append(`foto_${index}`, file);
});
const requestUrl = `{{ route('penilai.storeMemoWithPhotos') }}`; const requestUrl = `{{ route('penilai.storeMemoWithPhotos') }}`;
$.ajax({ $.ajax({
@@ -473,7 +520,7 @@
confirmButtonText: 'OK' confirmButtonText: 'OK'
}).then((response) => { }).then((response) => {
if (response.isConfirmed) { if (response.isConfirmed) {
// window.location.reload(); window.location.reload();
} }
}); });
} else { } else {

View File

@@ -0,0 +1,25 @@
{
"kepada": " rustam",
"dari": "dasd",
"nomor_memo": "C04\/250121588\/MAK\/REG0000014\/I\/25",
"tanggal": "2025-03-21",
"perihal": "te",
"jenis_asset_tidak_sesuai": "Alat Berat",
"lokasi": {
"lokasi": "dsad",
"address": "Jl. Kali Pasir Kecil No.1, RT.2\/RW.1, Cikini, Kec. Menteng, Kota Jakarta Pusat, Daerah Khusus Ibukota Jakarta 10330",
"province_code": "12",
"city_code": "",
"district_code": "",
"village_code": "",
"tanggal_survey": "2025-01-21 04:13:33",
"penilai": "rrer"
},
"terlampir": ["llorem"],
"hasil_survey": ["lorm"],
"kesimpulan_saran": ["loren"],
"foto": [
"temp_photos\/1742524956_1. Tampak Akses Jalan Menuju Objek Penilaian.png",
"temp_photos\/1742524957_2. Tampak Akses Jalan Menuju Objek penilaian.png"
]
}

View File

@@ -632,6 +632,7 @@ Route::middleware(['auth'])->group(function () {
Route::post('storeMemo', [PenilaiController::class, 'storeMemo'])->name('storeMemo'); Route::post('storeMemo', [PenilaiController::class, 'storeMemo'])->name('storeMemo');
Route::post('store-memo-with-photos', [PenilaiController::class, 'storeMemoWithPhotos'])->name('storeMemoWithPhotos'); Route::post('store-memo-with-photos', [PenilaiController::class, 'storeMemoWithPhotos'])->name('storeMemoWithPhotos');
Route::post('upload-temp-photo', [PenilaiController::class, 'uploadTempPhoto'])->name('uploadTempPhoto'); Route::post('upload-temp-photo', [PenilaiController::class, 'uploadTempPhoto'])->name('uploadTempPhoto');
Route::delete('delete-temp-photo', [PenilaiController::class, 'deleteTempPhoto'])->name('deleteTempPhoto');
Route::post('storeRap', [PenilaiController::class, 'storeRap'])->name('storeRap'); Route::post('storeRap', [PenilaiController::class, 'storeRap'])->name('storeRap');
Route::post('storeLpjSederhanadanStandard', [PenilaiController::class, 'storeLpjSederhanadanStandard'])->name('storeLpjSederhanadanStandard'); Route::post('storeLpjSederhanadanStandard', [PenilaiController::class, 'storeLpjSederhanadanStandard'])->name('storeLpjSederhanadanStandard');