From 6bbe35c4502771712a8561c8b80b981ccf918999 Mon Sep 17 00:00:00 2001 From: muamars Date: Thu, 5 Mar 2026 20:42:26 +0700 Subject: [PATCH] update: tps id dan detail non tps --- .../DetailPenjemputan/Index.cshtml | 2 +- .../DetailPenjemputan/TanpaTps.cshtml | 1005 +---------------- .../driver/js/detail-penjemputan-non-tps.js | 854 ++++++++++++++ ...njemputan.js => detail-penjemputan-tps.js} | 10 +- 4 files changed, 866 insertions(+), 1005 deletions(-) create mode 100644 wwwroot/driver/js/detail-penjemputan-non-tps.js rename wwwroot/driver/js/{detail-penjemputan.js => detail-penjemputan-tps.js} (98%) diff --git a/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/Index.cshtml b/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/Index.cshtml index a4fce0a..c6f2fab 100644 --- a/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/Index.cshtml +++ b/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/Index.cshtml @@ -127,5 +127,5 @@ @section Scripts { - + } \ No newline at end of file diff --git a/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/TanpaTps.cshtml b/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/TanpaTps.cshtml index fd794b5..3e3efd0 100644 --- a/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/TanpaTps.cshtml +++ b/Views/Admin/Transport/SpjDriverUpst/DetailPenjemputan/TanpaTps.cshtml @@ -113,1005 +113,6 @@ - - - +@section Scripts { + +} diff --git a/wwwroot/driver/js/detail-penjemputan-non-tps.js b/wwwroot/driver/js/detail-penjemputan-non-tps.js new file mode 100644 index 0000000..caabdac --- /dev/null +++ b/wwwroot/driver/js/detail-penjemputan-non-tps.js @@ -0,0 +1,854 @@ +document.addEventListener('DOMContentLoaded', function() { + const grandTotalDisplay = document.getElementById('grand-total-timbangan'); + const grandTotalOrganikDisplay = document.getElementById('grand-total-organik'); + const grandTotalAnorganikDisplay = document.getElementById('grand-total-anorganik'); + const grandTotalResiduDisplay = document.getElementById('grand-total-residu'); + const tpsContentContainer = document.getElementById('tps-content'); + + let activeTpsIndex = 0; + let tpsData = []; + let nomorSpj = 'SPJ/07-2025/PKM/000476'; + + const OCR_AREAS = [ + { id: 'A', x: 0.34, y: 0.35, w: 0.40, h: 0.11, color: 'border-lime-400 bg-lime-500/15' }, + { id: 'B', x: 0.31, y: 0.33, w: 0.45, h: 0.14, color: 'border-amber-300 bg-amber-400/10' }, + { id: 'C', x: 0.29, y: 0.31, w: 0.49, h: 0.17, color: 'border-cyan-300 bg-cyan-400/10' } + ]; + const JENIS_SAMPAH = ['Organik', 'Anorganik', 'Residu']; + const DEFAULT_JENIS = 'Residu'; + + function initializeLocation() { + tpsData = [{ + name: '', + index: 0, + lokasiAngkutId: '', + spjDetailId: '', + latitude: '', + longitude: '', + alamatJalan: '', + waktuKedatangan: '', + fotoKedatangan: [], + fotoKedatanganUploaded: false, + timbangan: [], + totalOrganik: 0, + totalAnorganik: 0, + totalResidu: 0, + totalTimbangan: 0, + fotoPetugas: [], + fotoPetugasUploaded: false, + namaPetugas: '', + submitted: false + }]; + + renderTpsForm(); + } + + function renderTpsForm() { + const tps = tpsData[activeTpsIndex]; + + tpsContentContainer.innerHTML = ` +
+ + + + + + + + + + +
+
+
1
+
+

Foto Kedatangan

+

Upload foto kedatangan

+
+
+ + + +
+ + ${tps.fotoKedatangan.length > 0 && !tps.fotoKedatanganUploaded ? ` + + ` : tps.fotoKedatanganUploaded ? ` +
+ ✓ Foto kedatangan sudah diupload +
+ ` : ''} + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ +
+
+
2
+
+

Foto Timbang Sampah

+

Upload foto timbangan, berat auto terisi

+
+
+ +
+ + +
+ +
+
+
3
+
+

Foto Petugas

+

Upload dokumentasi petugas

+
+
+ + + +
+ + ${tps.fotoPetugas.length > 0 && !tps.fotoPetugasUploaded ? ` + + ` : tps.fotoPetugasUploaded ? ` +
+ ✓ Foto petugas sudah diupload +
+ ` : ''} + +
+ + +
+
+ +
+ Batal + +
+
+ `; + + attachTpsFormListeners(); + restoreTpsTimbanganItems(); + restorePhotoPreview(); + } + + function restorePhotoPreview() { + const tps = tpsData[activeTpsIndex]; + const form = tpsContentContainer.querySelector('form'); + if (!form) return; + + const previewKedatangan = form.querySelector('.tps-preview-kedatangan'); + if (previewKedatangan && tps.fotoKedatangan.length > 0) { + renderStoredPhotos(tps.fotoKedatangan, previewKedatangan); + } + + const previewPetugas = form.querySelector('.tps-preview-petugas'); + if (previewPetugas && tps.fotoPetugas.length > 0) { + renderStoredPhotos(tps.fotoPetugas, previewPetugas); + } + } + + function renderStoredPhotos(files, container) { + container.innerHTML = ''; + container.className = 'space-y-2'; + + files.forEach((file, index) => { + const item = document.createElement('div'); + item.className = 'rounded-xl border border-gray-200 overflow-hidden bg-black'; + + const imageUrl = URL.createObjectURL(file); + const safeName = file.name.replace(/"/g, '"'); + item.innerHTML = ` +
+ Preview ${index + 1} +
+
+

${index + 1}. ${safeName}

+

${formatFileSize(file.size)}

+
+ `; + + const img = item.querySelector('.preview-multi-image'); + if (img) { + img.onload = function() { + URL.revokeObjectURL(imageUrl); + }; + } + container.appendChild(item); + }); + } + + function attachTpsFormListeners() { + const form = tpsContentContainer.querySelector('form'); + const tps = tpsData[activeTpsIndex]; + + const fotoKedatanganInput = form.querySelector('.tps-foto-kedatangan'); + const fotoPetugasInput = form.querySelector('.tps-foto-petugas'); + const namaPetugasInput = form.querySelector('.tps-nama-petugas'); + const btnAddTimbangan = form.querySelector('.tps-btn-add-timbangan'); + + fotoKedatanganInput.addEventListener('change', function() { + tps.fotoKedatangan = Array.from(this.files); + tps.fotoKedatanganUploaded = false; + updateWaktuKedatangan(); + updateMultiPreview(this, form.querySelector('.tps-preview-kedatangan')); + renderTpsForm(); + }); + + fotoPetugasInput.addEventListener('change', function() { + tps.fotoPetugas = Array.from(this.files); + tps.fotoPetugasUploaded = false; + updateMultiPreview(this, form.querySelector('.tps-preview-petugas')); + renderTpsForm(); + }); + + namaPetugasInput.addEventListener('input', function() { + tps.namaPetugas = this.value; + }); + + btnAddTimbangan.addEventListener('click', function() { + createTimbanganItem(form.querySelector('.tps-timbangan-repeater')); + }); + + const btnUploadKedatangan = form.querySelector('.tps-btn-upload-kedatangan'); + if (btnUploadKedatangan) { + btnUploadKedatangan.addEventListener('click', uploadFotoKedatangan); + } + + const btnUploadPetugas = form.querySelector('.tps-btn-upload-petugas'); + if (btnUploadPetugas) { + btnUploadPetugas.addEventListener('click', uploadFotoPetugas); + } + + form.addEventListener('submit', function(e) { + e.preventDefault(); + submitTpsData(); + }); + } + + function restoreTpsTimbanganItems() { + const tps = tpsData[activeTpsIndex]; + const form = tpsContentContainer.querySelector('form'); + const repeater = form.querySelector('.tps-timbangan-repeater'); + + if (tps.timbangan.length === 0) { + createTimbanganItem(repeater); + } else { + tps.timbangan.forEach(timb => createTimbanganItem(repeater, timb)); + } + } + + function updateWaktuKedatangan() { + const tps = tpsData[activeTpsIndex]; + const now = new Date(); + const formatted = now.toLocaleString('id-ID', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + tps.waktuKedatangan = formatted; + + const form = tpsContentContainer.querySelector('form'); + const displayWaktu = form.querySelector('.tps-waktu-kedatangan'); + if (displayWaktu) displayWaktu.value = formatted; + + getLocationUpdate(); + } + + function reverseGeocode(lat, lng) { + const tps = tpsData[activeTpsIndex]; + fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}`) + .then(res => res.json()) + .then(data => { + const address = data.display_name || `${lat}, ${lng}`; + tps.latitude = lat; + tps.longitude = lng; + tps.alamatJalan = address; + + const form = tpsContentContainer.querySelector('form'); + if (form) { + const latInput = form.querySelector('.tps-display-latitude'); + const lngInput = form.querySelector('.tps-display-longitude'); + if (latInput) latInput.value = lat; + if (lngInput) lngInput.value = lng; + } + }) + .catch(() => { + tps.latitude = lat; + tps.longitude = lng; + tps.alamatJalan = `${lat}, ${lng}`; + + const form = tpsContentContainer.querySelector('form'); + if (form) { + const latInput = form.querySelector('.tps-display-latitude'); + const lngInput = form.querySelector('.tps-display-longitude'); + if (latInput) latInput.value = lat; + if (lngInput) lngInput.value = lng; + } + }); + } + + function getLocationUpdate() { + if (!('geolocation' in navigator)) return; + + navigator.geolocation.getCurrentPosition( + function(position) { + const lat = position.coords.latitude.toFixed(6); + const lng = position.coords.longitude.toFixed(6); + reverseGeocode(lat, lng); + }, + function() { + console.log('Lokasi tidak diizinkan'); + } + ); + } + + function formatFileSize(bytes) { + const mb = bytes / (1024 * 1024); + return `${mb.toFixed(2)} MB`; + } + + function updateMultiPreview(input, previewContainer) { + if (!input || !previewContainer) return; + + previewContainer.innerHTML = ''; + previewContainer.className = 'space-y-2'; + + if (!input.files || input.files.length === 0) return; + + Array.from(input.files).forEach((file, index) => { + const item = document.createElement('div'); + item.className = 'rounded-xl border border-gray-200 overflow-hidden bg-black'; + + const imageUrl = URL.createObjectURL(file); + const safeName = file.name.replace(/"/g, '"'); + item.innerHTML = ` +
+ Preview ${index + 1} +
+
+

${index + 1}. ${safeName}

+

${formatFileSize(file.size)}

+
+ `; + + const img = item.querySelector('.preview-multi-image'); + if (img) { + img.onload = function() { + URL.revokeObjectURL(imageUrl); + }; + } + previewContainer.appendChild(item); + }); + } + + function formatWeightDisplay(value) { + if (isNaN(value)) return '0,00'; + return value.toFixed(2).replace('.', ','); + } + + function parseWeightInput(value) { + if (!value) return 0; + const cleaned = value.toString().trim().replace(/\s/g, '').replace(',', '.'); + const parsed = parseFloat(cleaned); + return isNaN(parsed) ? 0 : parsed; + } + + async function applyWatermark(file, photoNumber) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = function(e) { + const img = new Image(); + img.onload = function() { + const canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + + const now = new Date(); + const days = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu']; + const months = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des']; + const timestamp = `${days[now.getDay()]}, ${now.getDate().toString().padStart(2, '0')} ${months[now.getMonth()]} ${now.getFullYear()} • ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`; + + const baseFontSize = Math.max(16, Math.min(img.width, img.height) * 0.025); + const fontFamily = "'Montserrat', 'Segoe UI', 'Roboto', sans-serif"; + const lines = [ + { text: `FOTO TIMBANG #${photoNumber}`, size: baseFontSize * 1.1, weight: '900', color: '#FFD700' }, + { text: `${nomorSpj}`, size: baseFontSize * 0.9, weight: '700', color: '#FFFFFF' }, + { text: timestamp, size: baseFontSize * 0.75, weight: '500', color: '#E2E8F0' } + ]; + + const paddingX = baseFontSize * 1.2; + const paddingY = baseFontSize * 1.0; + const lineGap = baseFontSize * 0.4; + let maxWidth = 0; + let totalHeight = 0; + lines.forEach(line => { + ctx.font = `${line.weight} ${line.size}px ${fontFamily}`; + const metrics = ctx.measureText(line.text); + maxWidth = Math.max(maxWidth, metrics.width); + totalHeight += line.size + lineGap; + }); + totalHeight -= lineGap; + + const margin = baseFontSize * 1.5; + const boxWidth = maxWidth + (paddingX * 2); + const boxHeight = totalHeight + (paddingY * 2); + const boxX = img.width - boxWidth - margin; + const boxY = img.height - boxHeight - margin; + + ctx.beginPath(); + if (ctx.roundRect) { + ctx.roundRect(boxX, boxY, boxWidth, boxHeight, baseFontSize * 0.8); + } else { + ctx.rect(boxX, boxY, boxWidth, boxHeight); + } + ctx.fillStyle = 'rgba(15, 23, 42, 0.85)'; + ctx.fill(); + + const accentWidth = baseFontSize * 0.3; + ctx.beginPath(); + if (ctx.roundRect) { + ctx.roundRect(boxX + boxWidth - accentWidth, boxY, accentWidth, boxHeight, [0, baseFontSize * 0.8, baseFontSize * 0.8, 0]); + } else { + ctx.rect(boxX + boxWidth - accentWidth, boxY, accentWidth, boxHeight); + } + ctx.fillStyle = '#FFD700'; + ctx.fill(); + + ctx.textAlign = 'right'; + ctx.textBaseline = 'top'; + let currentY = boxY + paddingY; + const textRightLimit = boxX + boxWidth - paddingX - accentWidth; + lines.forEach(line => { + ctx.font = `${line.weight} ${line.size}px ${fontFamily}`; + ctx.fillStyle = line.color; + ctx.fillText(line.text, textRightLimit, currentY); + currentY += line.size + lineGap; + }); + + canvas.toBlob(function(blob) { + const watermarkedFile = new File([blob], file.name, { + type: 'image/jpeg', + lastModified: Date.now() + }); + resolve(watermarkedFile); + }, 'image/jpeg', 0.95); + }; + img.onerror = reject; + img.src = e.target.result; + }; + reader.onerror = reject; + reader.readAsDataURL(file); + }); + } + + function readFileAsImage(file) { + return new Promise(function(resolve, reject) { + const objectUrl = URL.createObjectURL(file); + const img = new Image(); + img.onload = function() { + URL.revokeObjectURL(objectUrl); + resolve(img); + }; + img.onerror = function() { + URL.revokeObjectURL(objectUrl); + reject(new Error('Gagal membaca gambar.')); + }; + img.src = objectUrl; + }); + } + + function createCropCanvas(img, area) { + const sx = Math.max(0, Math.floor(img.width * area.x)); + const sy = Math.max(0, Math.floor(img.height * area.y)); + const sw = Math.max(1, Math.floor(img.width * area.w)); + const sh = Math.max(1, Math.floor(img.height * area.h)); + const canvas = document.createElement('canvas'); + const scale = 2.2; + canvas.width = Math.max(1, Math.floor(sw * scale)); + canvas.height = Math.max(1, Math.floor(sh * scale)); + const ctx = canvas.getContext('2d'); + if (!ctx) return canvas; + ctx.imageSmoothingEnabled = true; + ctx.drawImage(img, sx, sy, sw, sh, 0, 0, canvas.width, canvas.height); + return canvas; + } + + function canvasToJpegFile(canvas, fileName) { + return new Promise(function(resolve, reject) { + canvas.toBlob(function(blob) { + if (!blob) { + reject(new Error('Gagal membuat crop image.')); + return; + } + resolve(new File([blob], fileName, { type: 'image/jpeg' })); + }, 'image/jpeg', 0.92); + }); + } + + async function requestOpenRouterWeight(imageFile) { + const formData = new FormData(); + formData.append('Foto', imageFile); + const response = await fetch('/upst/detail-penjemputan/ocr-timbangan', { method: 'POST', body: formData }); + const result = await response.json(); + if (!response.ok) throw new Error(result.message || 'Request OCR gagal.'); + return result; + } + + async function autoFillWeight(file, weightInput, ocrInfoEl) { + let guessedWeight = 0; + weightInput.placeholder = 'Membaca angka dari foto...'; + if (ocrInfoEl) ocrInfoEl.textContent = 'AI OCR: memproses gambar...'; + + try { + const img = await readFileAsImage(file); + let bestRawText = ''; + let isSuccess = false; + + for (const area of OCR_AREAS) { + const cropCanvas = createCropCanvas(img, area); + const cropFile = await canvasToJpegFile(cropCanvas, `crop-${area.id}.jpg`); + const aiResult = await requestOpenRouterWeight(cropFile); + + if (aiResult && aiResult.success && aiResult.weight) { + guessedWeight = parseWeightInput(aiResult.weight); + bestRawText = aiResult.raw || aiResult.weight; + isSuccess = guessedWeight > 0; + if (isSuccess) break; + } + + if (aiResult && aiResult.raw) bestRawText = aiResult.raw; + } + + if (ocrInfoEl) { + const cleaned = (bestRawText || '').replace(/\s+/g, ' ').trim(); + ocrInfoEl.textContent = isSuccess + ? `AI OCR terbaca: ${cleaned}` + : (cleaned ? `AI OCR tidak valid: ${cleaned}` : 'AI OCR tidak menemukan angka valid.'); + } + } catch (_) { + guessedWeight = 0; + if (ocrInfoEl) ocrInfoEl.textContent = 'AI OCR gagal diproses.'; + } + + if (guessedWeight > 0) { + weightInput.value = formatWeightDisplay(guessedWeight); + weightInput.placeholder = 'Berat terdeteksi otomatis'; + } else { + weightInput.placeholder = 'Tidak terbaca otomatis, isi manual'; + } + + updateTpsTotalTimbangan(); + } + + function updateTpsTotalTimbangan() { + const tps = tpsData[activeTpsIndex]; + const form = tpsContentContainer.querySelector('form'); + if (!form) return; + + let totalOrganik = 0.0; + let totalAnorganik = 0.0; + let totalResidu = 0.0; + const repeater = form.querySelector('.tps-timbangan-repeater'); + const items = repeater.querySelectorAll('.timbangan-item'); + + items.forEach(function(item) { + const weightInput = item.querySelector('.input-berat-timbangan-value'); + const jenisSampahSelect = item.querySelector('.input-jenis-sampah'); + if (weightInput && jenisSampahSelect) { + const value = parseWeightInput(weightInput.value || '0'); + const jenis = jenisSampahSelect.value; + if (jenis === 'Organik') totalOrganik += value; + else if (jenis === 'Anorganik') totalAnorganik += value; + else totalResidu += value; + } + }); + + tps.totalOrganik = totalOrganik; + tps.totalAnorganik = totalAnorganik; + tps.totalResidu = totalResidu; + tps.totalTimbangan = totalOrganik + totalAnorganik + totalResidu; + + const displayTotal = form.querySelector('.tps-display-total'); + if (displayTotal) displayTotal.textContent = formatWeightDisplay(tps.totalTimbangan); + + if (grandTotalDisplay) grandTotalDisplay.textContent = formatWeightDisplay(tps.totalTimbangan); + if (grandTotalOrganikDisplay) grandTotalOrganikDisplay.textContent = formatWeightDisplay(totalOrganik); + if (grandTotalAnorganikDisplay) grandTotalAnorganikDisplay.textContent = formatWeightDisplay(totalAnorganik); + if (grandTotalResiduDisplay) grandTotalResiduDisplay.textContent = formatWeightDisplay(totalResidu); + } + + function createTimbanganItem(repeater, existingData = null) { + const item = document.createElement('div'); + item.className = 'timbangan-item rounded-2xl border border-gray-200 p-3 space-y-2 bg-gray-50'; + + const weight = existingData ? existingData.weight : 0; + const jenisSampah = existingData ? (existingData.jenisSampah || DEFAULT_JENIS) : DEFAULT_JENIS; + const hasFile = existingData && existingData.file; + const isUploaded = existingData && existingData.uploaded; + + item.innerHTML = ` +
+

Item Timbangan

+ +
+ +
+ Preview foto timbangan +
+
+

${hasFile ? 'OCR: diproses.' : 'OCR: belum diproses.'}

+ ${hasFile && !isUploaded ? ` + + ` : isUploaded ? `
✓ Foto timbangan sudah diupload
` : ''} +
+
+ + +
+
+ + + +
+
+ `; + + const fileInput = item.querySelector('.input-foto-timbangan'); + const previewWrap = item.querySelector('.input-preview-wrap'); + const previewImage = item.querySelector('.input-preview-image'); + const ocrInfoEl = item.querySelector('.input-ocr-info'); + const weightInputDisplay = item.querySelector('.input-berat-timbangan-display'); + const weightInputValue = item.querySelector('.input-berat-timbangan-value'); + const jenisSampahSelect = item.querySelector('.input-jenis-sampah'); + const removeBtn = item.querySelector('.btn-remove-timbangan'); + + if (existingData && existingData.file) { + const localUrl = URL.createObjectURL(existingData.file); + previewImage.src = localUrl; + previewImage.onload = function() { URL.revokeObjectURL(localUrl); }; + } + + fileInput.addEventListener('change', async function() { + if (fileInput.files && fileInput.files[0]) { + const originalFile = fileInput.files[0]; + const photoNumber = Array.from(repeater.children).indexOf(item) + 1; + const watermarkedFile = await applyWatermark(originalFile, photoNumber); + + const dataTransfer = new DataTransfer(); + dataTransfer.items.add(watermarkedFile); + fileInput.files = dataTransfer.files; + + const localUrl = URL.createObjectURL(watermarkedFile); + previewImage.src = localUrl; + previewWrap.classList.remove('hidden'); + previewImage.onload = function() { URL.revokeObjectURL(localUrl); }; + + await autoFillWeight(watermarkedFile, weightInputDisplay, ocrInfoEl); + const parsed = parseWeightInput(weightInputDisplay.value); + weightInputValue.value = parsed.toFixed(2); + updateTpsTotalTimbangan(); + syncTimbanganToTpsData(); + + const tps = tpsData[activeTpsIndex]; + const itemIndex = Array.from(repeater.children).indexOf(item); + if (itemIndex >= 0 && tps.timbangan[itemIndex]) { + tps.timbangan[itemIndex].uploaded = false; + const existingUploadBtn = item.querySelector('.btn-upload-timbangan'); + if (!existingUploadBtn) { + const ocrInfo = item.querySelector('.input-ocr-info'); + const uploadBtn = document.createElement('button'); + uploadBtn.type = 'button'; + uploadBtn.className = 'btn-upload-timbangan w-full bg-blue-500 text-white py-2 rounded-xl font-bold text-xs hover:brightness-110'; + uploadBtn.textContent = 'Upload Foto Timbangan Ini'; + uploadBtn.addEventListener('click', function() { uploadSingleFotoTimbangan(itemIndex); }); + ocrInfo.parentNode.insertBefore(uploadBtn, ocrInfo.nextSibling); + } + } + } + }); + + weightInputDisplay.addEventListener('input', function() { + const cleaned = this.value.replace(/[^0-9.,]/g, ''); + this.value = cleaned; + const parsed = parseWeightInput(cleaned); + weightInputValue.value = parsed.toFixed(2); + updateTpsTotalTimbangan(); + syncTimbanganToTpsData(); + }); + + weightInputDisplay.addEventListener('blur', function() { + const parsed = parseWeightInput(this.value); + if (parsed > 0) { + this.value = formatWeightDisplay(parsed); + weightInputValue.value = parsed.toFixed(2); + } else { + this.value = ''; + weightInputValue.value = '0.00'; + } + updateTpsTotalTimbangan(); + syncTimbanganToTpsData(); + }); + + jenisSampahSelect.addEventListener('change', function() { + updateTpsTotalTimbangan(); + syncTimbanganToTpsData(); + }); + + removeBtn.addEventListener('click', function() { + item.remove(); + const form = tpsContentContainer.querySelector('form'); + const rep = form ? form.querySelector('.tps-timbangan-repeater') : null; + if (rep && rep.children.length === 0) createTimbanganItem(rep); + updateTpsTotalTimbangan(); + syncTimbanganToTpsData(); + }); + + const btnUploadTimbangan = item.querySelector('.btn-upload-timbangan'); + if (btnUploadTimbangan) { + btnUploadTimbangan.addEventListener('click', function() { + const itemIndex = Array.from(repeater.children).indexOf(item); + uploadSingleFotoTimbangan(itemIndex); + }); + } + + repeater.appendChild(item); + return item; + } + + function syncTimbanganToTpsData() { + const tps = tpsData[activeTpsIndex]; + const form = tpsContentContainer.querySelector('form'); + if (!form) return; + + const repeater = form.querySelector('.tps-timbangan-repeater'); + const items = repeater.querySelectorAll('.timbangan-item'); + + tps.timbangan = []; + items.forEach(item => { + const fileInput = item.querySelector('.input-foto-timbangan'); + const weightValue = item.querySelector('.input-berat-timbangan-value'); + tps.timbangan.push({ + file: fileInput.files[0] || null, + weight: parseWeightInput(weightValue.value), + jenisSampah: item.querySelector('.input-jenis-sampah').value, + uploaded: false + }); + }); + } + + function buildSubmitFormData(tps) { + const formData = new FormData(); + formData.append('LokasiAngkutID', tps.lokasiAngkutId || ''); + formData.append('SpjDetailID', tps.spjDetailId || ''); + formData.append('Latitude', tps.latitude); + formData.append('Longitude', tps.longitude); + formData.append('AlamatJalan', tps.alamatJalan); + formData.append('WaktuKedatangan', tps.waktuKedatangan); + formData.append('TotalTimbangan', tps.totalTimbangan); + formData.append('TotalOrganik', tps.totalOrganik); + formData.append('TotalAnorganik', tps.totalAnorganik); + formData.append('TotalResidu', tps.totalResidu); + formData.append('NamaPetugas', tps.namaPetugas); + + tps.fotoKedatangan.forEach((file) => formData.append('FotoKedatangan', file)); + tps.timbangan.forEach((timb) => { + if (timb.file) formData.append('FotoTimbangan', timb.file); + formData.append('BeratTimbangan', timb.weight); + formData.append('JenisSampahList', timb.jenisSampah || DEFAULT_JENIS); + }); + tps.fotoPetugas.forEach((file) => formData.append('FotoPetugas', file)); + + const antiForgeryTokenEl = document.querySelector('#upst-antiforgery input[name="__RequestVerificationToken"]'); + if (antiForgeryTokenEl && antiForgeryTokenEl.value) { + formData.append('__RequestVerificationToken', antiForgeryTokenEl.value); + } + + return formData; + } + + function uploadSingleFotoTimbangan(itemIndex) { + const tps = tpsData[activeTpsIndex]; + if (!tps.timbangan[itemIndex] || !tps.timbangan[itemIndex].file) { + alert('Belum ada foto timbangan yang dipilih!'); + return; + } + alert(`Upload foto timbangan #${itemIndex + 1}\nBerat: ${tps.timbangan[itemIndex].weight} kg\n(Implementasi upload ke server)`); + tps.timbangan[itemIndex].uploaded = true; + } + + function uploadFotoKedatangan() { + const tps = tpsData[activeTpsIndex]; + if (tps.fotoKedatangan.length === 0) { + alert('Belum ada foto kedatangan yang dipilih!'); + return; + } + alert(`Upload ${tps.fotoKedatangan.length} foto kedatangan\n(Implementasi upload ke server)`); + tps.fotoKedatanganUploaded = true; + renderTpsForm(); + } + + function uploadFotoPetugas() { + const tps = tpsData[activeTpsIndex]; + if (tps.fotoPetugas.length === 0) { + alert('Belum ada foto petugas yang dipilih!'); + return; + } + alert(`Upload ${tps.fotoPetugas.length} foto petugas\n(Implementasi upload ke server)`); + tps.fotoPetugasUploaded = true; + renderTpsForm(); + } + + function submitTpsData() { + const tps = tpsData[activeTpsIndex]; + if (!tps.fotoKedatangan.length) return alert('Foto kedatangan belum diupload!'); + if (!tps.timbangan.length) return alert('Belum ada data timbangan!'); + if (!tps.fotoPetugas.length) return alert('Foto petugas belum diupload!'); + if (!tps.namaPetugas.trim()) return alert('Nama petugas belum diisi!'); + + alert(`Validasi OK (Tanpa TPS).\n- Organik: ${formatWeightDisplay(tps.totalOrganik)} kg\n- Anorganik: ${formatWeightDisplay(tps.totalAnorganik)} kg\n- Residu: ${formatWeightDisplay(tps.totalResidu)} kg\n- Total: ${formatWeightDisplay(tps.totalTimbangan)} kg\n- Petugas: ${tps.namaPetugas}`); + tps.submitted = true; + + /* + const formData = buildSubmitFormData(tps); + fetch('/upst/detail-penjemputan', { method: 'POST', body: formData }); + */ + } + + const nomorSpjEl = document.querySelector('.text-gray-600.font-mono'); + if (nomorSpjEl && nomorSpjEl.textContent) { + nomorSpj = nomorSpjEl.textContent.trim(); + } + + initializeLocation(); +}); diff --git a/wwwroot/driver/js/detail-penjemputan.js b/wwwroot/driver/js/detail-penjemputan-tps.js similarity index 98% rename from wwwroot/driver/js/detail-penjemputan.js rename to wwwroot/driver/js/detail-penjemputan-tps.js index 2ede325..9fed49c 100644 --- a/wwwroot/driver/js/detail-penjemputan.js +++ b/wwwroot/driver/js/detail-penjemputan-tps.js @@ -82,9 +82,11 @@ const DetailPenjemputan = (function() { } function initializeTpsData(tpsNames) { - state.tpsData = tpsNames.map((name, index) => ({ - name: name, + state.tpsData = tpsNames.map((tpsItem, index) => ({ + name: typeof tpsItem === 'string' ? tpsItem : (tpsItem?.name || tpsItem?.Name || `TPS ${index + 1}`), index: index, + lokasiAngkutId: typeof tpsItem === 'string' ? '' : (tpsItem?.lokasiAngkutId || tpsItem?.LokasiAngkutID || ''), + spjDetailId: typeof tpsItem === 'string' ? '' : (tpsItem?.spjDetailId || tpsItem?.SpjDetailID || ''), latitude: '', longitude: '', alamatJalan: '', @@ -205,6 +207,8 @@ const DetailPenjemputan = (function() { elements.tpsContentContainer.innerHTML = `
+ + @@ -1101,6 +1105,8 @@ async function applyWatermark(file, photoNumber) { function buildSubmitFormData(tps) { const formData = new FormData(); + formData.append('LokasiAngkutID', tps.lokasiAngkutId || ''); + formData.append('SpjDetailID', tps.spjDetailId || ''); formData.append('TpsName', tps.name); formData.append('Latitude', tps.latitude); formData.append('Longitude', tps.longitude);