fix(memo): perbaikkan upload foto di memo, foto existing hilang ketika upload ulang
This commit is contained in:
@@ -834,13 +834,13 @@ class PenilaiController extends Controller
|
||||
}
|
||||
|
||||
|
||||
$cekLpj =$this->checkDataLpj($type, $statusLpj)
|
||||
if ($permohonan->status_bayar === 'sudah_bayar' && $cekLpj) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Harap mengisi LPJ terlebih dahulu',
|
||||
])
|
||||
}
|
||||
// $cekLpj = $this->checkDataLpj($type, $statusLpj);
|
||||
// if ($permohonan->status_bayar === 'sudah_bayar' && $cekLpj) {
|
||||
// return response()->json([
|
||||
// 'success' => false,
|
||||
// 'message' => 'Harap mengisi LPJ terlebih dahulu',
|
||||
// ]);
|
||||
// }
|
||||
|
||||
|
||||
$permohonan->update([
|
||||
@@ -862,14 +862,69 @@ class PenilaiController extends Controller
|
||||
|
||||
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')) {
|
||||
$file = $request->file('file');
|
||||
$filename = time() . '_' . $file->getClientOriginalName();
|
||||
$path = $file->storeAs('temp_photos', $filename, 'public');
|
||||
return response()->json(['success' => true, 'id' => $path]);
|
||||
|
||||
$files = $request->file('file');
|
||||
|
||||
if (!is_array($files)) {
|
||||
$files = [$files];
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
|
||||
$filename = time() . '_' . $file->getClientOriginalName();
|
||||
$path = $file->storeAs('temp_photos', $filename, 'public');
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
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], 400);
|
||||
return response()->json(['success' => false, 'message' => 'Foto tidak ditemukan'], 400);
|
||||
}
|
||||
|
||||
public function storeResume(Request $request)
|
||||
@@ -964,42 +1019,20 @@ class PenilaiController extends Controller
|
||||
'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'],
|
||||
'dokument_id' => $validatedData['document_id'],
|
||||
|
||||
],
|
||||
[
|
||||
'memo' => json_encode($memoData),
|
||||
]
|
||||
);
|
||||
|
||||
// $existingPhotos = isset($memo->memo) ? json_decode($memo->memo) : [];
|
||||
// dd($existingPhotos);
|
||||
// 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++;
|
||||
}
|
||||
$existingMemoData = isset($memo->memo) ? json_decode($memo->memo, true) : [];
|
||||
$mergedMemoData = array_merge($existingMemoData, $newMemoData);
|
||||
|
||||
// $memoData['foto'] = array_merge($existingPhotos, $photoUrls);
|
||||
|
||||
// }else{
|
||||
// $memoData['foto'] = $existingPhotos;
|
||||
// Tambahkan URL foto ke data memo
|
||||
$memoData['foto'] = $photoUrls;
|
||||
$memo->memo = json_encode($memoData);
|
||||
$memo->memo = json_encode($mergedMemoData);
|
||||
$memo->save();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
@@ -1077,7 +1110,7 @@ class PenilaiController extends Controller
|
||||
'message' => 'Berhasil menyimpan LPJ',
|
||||
'data' => $result
|
||||
], 200);
|
||||
}catch (\Throwable $e) {
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
|
||||
@@ -186,7 +186,8 @@
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<input type="date-time" id="tanggal_survey" name="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>
|
||||
|
||||
@@ -315,10 +316,11 @@
|
||||
|
||||
<div class="flex card-footer justify-end gap-5">
|
||||
@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' : '' }}>
|
||||
<i class="ki-filled ki-save-2"></i>
|
||||
Simpan
|
||||
</a>
|
||||
<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>
|
||||
Simpan
|
||||
</a>
|
||||
@endif
|
||||
@if (Auth::user()->hasAnyRole(['administrator', 'senior-officer', 'EO Appraisal', 'DD Appraisal']))
|
||||
<a class="btn btn-info"
|
||||
@@ -347,11 +349,13 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
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",
|
||||
maxFilesize: 5, // MB
|
||||
acceptedFiles: "image/*",
|
||||
addRemoveLinks: true,
|
||||
uploadMultiple: false,
|
||||
parallelUploads: 1,
|
||||
autoProcessQueue: true,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
@@ -370,132 +374,175 @@
|
||||
const existingPhotosContainer = document.getElementById('existing-photos');
|
||||
if (!existingPhotosContainer) return;
|
||||
|
||||
@if(isset($memo) && isset($memo->foto))
|
||||
let existingPhotos;
|
||||
try {
|
||||
existingPhotos = @json($memo->foto);
|
||||
} catch (e) {
|
||||
console.error('Error parsing existing photos:', e);
|
||||
return;
|
||||
}
|
||||
@if (isset($memo) && isset($memo->foto))
|
||||
let existingPhotos;
|
||||
try {
|
||||
existingPhotos = @json($memo->foto);
|
||||
} catch (e) {
|
||||
console.error('Error parsing existing photos:', e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(existingPhotos)) {
|
||||
existingPhotos.forEach(function(photoPath) {
|
||||
if (typeof photoPath === 'string') {
|
||||
const photoDiv = document.createElement('div');
|
||||
photoDiv.className = 'col-md-3 mb-3';
|
||||
if (Array.isArray(existingPhotos)) {
|
||||
const BASE_URL = "{{ asset('storage/') }}";
|
||||
existingPhotos.forEach(function(photoPath) {
|
||||
if (typeof photoPath === 'string') {
|
||||
const photoDiv = document.createElement('div');
|
||||
photoDiv.className = 'col-md-3 mb-3';
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.src = photoPath;
|
||||
img.className = 'img-fluid';
|
||||
img.style.maxHeight = '150px';
|
||||
const img = document.createElement('img');
|
||||
img.src = BASE_URL + '/' + photoPath;
|
||||
img.className = 'img-fluid';
|
||||
img.style.maxHeight = '150px';
|
||||
const deleteButton = document.createElement('button');
|
||||
|
||||
photoDiv.appendChild(img);
|
||||
existingPhotosContainer.appendChild(photoDiv);
|
||||
deleteButton.className = 'btn btn-danger btn-sm mt-2';
|
||||
deleteButton.textContent = 'Hapus';
|
||||
deleteButton.type = 'button';
|
||||
deleteButton.onclick = function() {
|
||||
handleDeletePhoto(photoPath, photoDiv);
|
||||
};
|
||||
|
||||
if (myDropzone) {
|
||||
let mockFile = { name: photoPath.split('/').pop(), size: 12345 };
|
||||
myDropzone.emit("addedfile", mockFile);
|
||||
myDropzone.emit("thumbnail", mockFile, photoPath);
|
||||
myDropzone.emit("complete", mockFile);
|
||||
mockFile.previewElement.classList.add("dz-success");
|
||||
mockFile.previewElement.classList.add("dz-complete");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('Existing photos is not an array:', existingPhotos);
|
||||
}
|
||||
@endif
|
||||
}
|
||||
photoDiv.appendChild(img);
|
||||
photoDiv.appendChild(deleteButton);
|
||||
existingPhotosContainer.appendChild(photoDiv);
|
||||
|
||||
function saveMemo() {
|
||||
const form = document.getElementById('form-memo');
|
||||
const formData = new FormData(form);
|
||||
|
||||
const jsonData = {
|
||||
kepada: formData.get('kepada'),
|
||||
dari: formData.get('dari'),
|
||||
nomor_memo: formData.get('nomor_memo'),
|
||||
tanggal: formData.get('tanggal'),
|
||||
perihal: formData.get('perihal'),
|
||||
jenis_asset_tidak_sesuai: formData.get('jenis_asset_tidak_sesuai'),
|
||||
lokasi: {
|
||||
lokasi: formData.get('lokasi') || '',
|
||||
address: formData.get('address') || '',
|
||||
province_code: formData.get('province_code') || '',
|
||||
city_code: formData.get('city_code') || '',
|
||||
district_code: formData.get('district_code') || '',
|
||||
village_code: formData.get('village_code') || '',
|
||||
tanggal_survey: formData.get('tanggal_survey') || '',
|
||||
penilai: formData.get('penilai') || '',
|
||||
},
|
||||
terlampir: (formData.getAll('terlampir[]') || []),
|
||||
hasil_survey: (formData.getAll('hasil_survey[]') || []),
|
||||
kesimpulan_saran: (formData.getAll('kesimpulan_saran[]') || []),
|
||||
};
|
||||
|
||||
showLoadingSwal('Mengirim data ke server...');
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const permohonanId = urlParams.get('permohonanId');
|
||||
const documentId = urlParams.get('documentId');
|
||||
|
||||
// Create a new FormData object to send both JSON and files
|
||||
const sendFormData = new FormData();
|
||||
sendFormData.append('permohonan_id', permohonanId);
|
||||
sendFormData.append('document_id', documentId);
|
||||
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') }}`;
|
||||
|
||||
$.ajax({
|
||||
url: requestUrl,
|
||||
type: 'POST',
|
||||
data: sendFormData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
success: function(response) {
|
||||
hideLoadingSwal();
|
||||
if (response.success) {
|
||||
Swal.fire({
|
||||
title: 'Berhasil!',
|
||||
text: response.message,
|
||||
icon: 'success',
|
||||
confirmButtonText: 'OK'
|
||||
}).then((response) => {
|
||||
if (response.isConfirmed) {
|
||||
// window.location.reload();
|
||||
if (myDropzone) {
|
||||
let mockFile = {
|
||||
name: photoPath.split('/').pop(),
|
||||
size: 12345
|
||||
};
|
||||
myDropzone.emit("addedfile", mockFile);
|
||||
myDropzone.emit("thumbnail", mockFile, photoPath);
|
||||
myDropzone.emit("complete", mockFile);
|
||||
mockFile.previewElement.classList.add("dz-success");
|
||||
mockFile.previewElement.classList.add("dz-complete");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('Existing photos is not an array:', existingPhotos);
|
||||
}
|
||||
@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() {
|
||||
const form = document.getElementById('form-memo');
|
||||
const formData = new FormData(form);
|
||||
|
||||
const jsonData = {
|
||||
kepada: formData.get('kepada'),
|
||||
dari: formData.get('dari'),
|
||||
nomor_memo: formData.get('nomor_memo'),
|
||||
tanggal: formData.get('tanggal'),
|
||||
perihal: formData.get('perihal'),
|
||||
jenis_asset_tidak_sesuai: formData.get('jenis_asset_tidak_sesuai'),
|
||||
lokasi: {
|
||||
lokasi: formData.get('lokasi') || '',
|
||||
address: formData.get('address') || '',
|
||||
province_code: formData.get('province_code') || '',
|
||||
city_code: formData.get('city_code') || '',
|
||||
district_code: formData.get('district_code') || '',
|
||||
village_code: formData.get('village_code') || '',
|
||||
tanggal_survey: formData.get('tanggal_survey') || '',
|
||||
penilai: formData.get('penilai') || '',
|
||||
},
|
||||
terlampir: (formData.getAll('terlampir[]') || []),
|
||||
hasil_survey: (formData.getAll('hasil_survey[]') || []),
|
||||
kesimpulan_saran: (formData.getAll('kesimpulan_saran[]') || []),
|
||||
};
|
||||
|
||||
showLoadingSwal('Mengirim data ke server...');
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const permohonanId = urlParams.get('permohonanId');
|
||||
const documentId = urlParams.get('documentId');
|
||||
|
||||
// Create a new FormData object to send both JSON and files
|
||||
const sendFormData = new FormData();
|
||||
sendFormData.append('permohonan_id', permohonanId);
|
||||
sendFormData.append('document_id', documentId);
|
||||
sendFormData.append('memo', JSON.stringify(jsonData));
|
||||
|
||||
const requestUrl = `{{ route('penilai.storeMemoWithPhotos') }}`;
|
||||
|
||||
$.ajax({
|
||||
url: requestUrl,
|
||||
type: 'POST',
|
||||
data: sendFormData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
success: function(response) {
|
||||
hideLoadingSwal();
|
||||
if (response.success) {
|
||||
Swal.fire({
|
||||
title: 'Berhasil!',
|
||||
text: response.message,
|
||||
icon: 'success',
|
||||
confirmButtonText: 'OK'
|
||||
}).then((response) => {
|
||||
if (response.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message || 'Terjadi kesalahan',
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
}
|
||||
console.log(response);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
hideLoadingSwal();
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message || 'Terjadi kesalahan',
|
||||
text: 'Terjadi kesalahan saat mengirim data',
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
}
|
||||
console.log(response);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
hideLoadingSwal();
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: 'Terjadi kesalahan saat mengirim data',
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
25
resources/views/penilai/data.json
Normal file
25
resources/views/penilai/data.json
Normal 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"
|
||||
]
|
||||
}
|
||||
@@ -632,6 +632,7 @@ Route::middleware(['auth'])->group(function () {
|
||||
Route::post('storeMemo', [PenilaiController::class, 'storeMemo'])->name('storeMemo');
|
||||
Route::post('store-memo-with-photos', [PenilaiController::class, 'storeMemoWithPhotos'])->name('storeMemoWithPhotos');
|
||||
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('storeLpjSederhanadanStandard', [PenilaiController::class, 'storeLpjSederhanadanStandard'])->name('storeLpjSederhanadanStandard');
|
||||
|
||||
Reference in New Issue
Block a user