diff --git a/Layout/default/VueViews/WorkorderCompanyPWA.php b/Layout/default/VueViews/WorkorderCompanyPWA.php index 27ef3c832..37634e7dd 100644 --- a/Layout/default/VueViews/WorkorderCompanyPWA.php +++ b/Layout/default/VueViews/WorkorderCompanyPWA.php @@ -115,6 +115,7 @@ const isSettingsOpen = ref(false); const theme = ref('system'); // 'light', 'dark', 'system' const showThemePicker = ref(false); + const savingData = ref(false); // <-- ADDED const API_BASE_URL = window.TT_CONFIG.BASE_PATH || '/WorkorderCompany'; @@ -211,9 +212,24 @@ }); }); + // MODIFIED const isChecklistComplete = computed(() => { - if (checklist.value.length === 0) return true; - return checklist.value.every(item => item.completed); + // Check documents + if (checklist.value.length > 0) { + if (!checklist.value.every(item => item.completed)) { + return false; + } + } + + // Check new fields + if (tenantConfig.value?.requireCableLength && (!selectedWorkorder.value.cableLength || !selectedWorkorder.value.cableLength.trim())) { + return false; + } + if (tenantConfig.value?.requireCableType && (!selectedWorkorder.value.cableType || !selectedWorkorder.value.cableType.trim())) { + return false; + } + + return true; // All checks passed }); const translatedDocs = computed(() => { @@ -291,7 +307,7 @@ documentation.docs = docRes.data.docs.map(d => ({...d, isPdf: d.mimetype === 'application/pdf'})); documentation.journals = docRes.data.journals; if (configRes.data.success) { - tenantConfig.value = configRes.data; + tenantConfig.value = configRes.data; // <-- MODIFIED: This will now contain all flags } } catch (e) { console.error("Could not load details", e); } finally { isDetailsLoading.value = false; } @@ -329,6 +345,36 @@ finally { isEditingInfo.value = false; } }; + // START ADDED + const saveWorkorderData = async () => { + savingData.value = true; + try { + const response = await api.post('/updateWorkorderData', { + workorderId: selectedWorkorder.value.id, + cableLength: selectedWorkorder.value.cableLength, + cableType: selectedWorkorder.value.cableType + }); + if (response.data.success) { + alert('Daten gespeichert.'); // PWA uses alert() + documentation.journals = response.data.journals; // Update journal + // Also update the main list item + const woInList = workorders.value.find(w => w.id === selectedWorkorder.value.id); + if (woInList) { + woInList.cableLength = selectedWorkorder.value.cableLength; + woInList.cableType = selectedWorkorder.value.cableType; + } + } else { + alert(response.data.message || 'Speichern fehlgeschlagen.'); + } + } catch (e) { + console.error("Failed to save data", e); + alert('Ein Netzwerkfehler ist aufgetreten.'); + } finally { + savingData.value = false; + } + }; + // END ADDED + const addJournalEntry = async () => { if (!newJournalEntry.value.trim()) return; try { @@ -401,13 +447,23 @@ finally { problemModal.show = false; problemModal.selectedInterventions = []; problemModal.details = {}; } }; + // MODIFIED const handleCompleteClick = () => { if (isChecklistComplete.value) { if (confirm("Möchten Sie diesen Auftrag wirklich abschließen?")) { completeWorkorder(); } } else { - missingTasksPopover.tasks = checklist.value.filter(t => !t.completed).map(t => t.text); + const missingDocs = checklist.value.filter(t => !t.completed).map(t => t.text); + const missingData = []; + if (tenantConfig.value?.requireCableLength && (!selectedWorkorder.value.cableLength || !selectedWorkorder.value.cableLength.trim())) { + missingData.push("Kabellänge"); + } + if (tenantConfig.value?.requireCableType && (!selectedWorkorder.value.cableType || !selectedWorkorder.value.cableType.trim())) { + missingData.push("Kabeltyp"); + } + + missingTasksPopover.tasks = [...missingDocs, ...missingData]; missingTasksPopover.show = true; setTimeout(() => missingTasksPopover.show = false, 4000); } @@ -415,10 +471,18 @@ const completeWorkorder = async () => { try { - await api.post('/completeWorkorder', { workorderId: selectedWorkorder.value.id }); - await fetchWorkorders(); - closeDetails(); - } catch(e) { console.error("Failed to complete workorder", e); } + // Server-side validation will catch errors if client-side check fails + const response = await api.post('/completeWorkorder', { workorderId: selectedWorkorder.value.id }); + if (response.data.success) { + await fetchWorkorders(); + closeDetails(); + } else { + alert(response.data.message); // Show validation error from server + } + } catch(e) { + console.error("Failed to complete workorder", e); + alert(e.response?.data?.message || 'Fehler beim Abschließen.'); + } }; const selectFcp = (fcpValue) => { @@ -456,8 +520,10 @@ checklist, fullscreenViewer, missingTasksPopover, translatedDocs, filteredJournals, installModal, isStandalone, selectedFcp, isFcpSelectOpen, fcpOptions, selectedFcpText, fcpSearchTerm, filteredFcpOptions, fcpInputRef, isSettingsOpen, theme, showThemePicker, + savingData, // <-- ADDED fetchWorkorders, openDetails, closeDetails, getStatusInfo, formatDate, googleMapsLink, startEditInfo, saveAdditionalInfo, - handleFileSelect, executeUpload, addJournalEntry, submitProblem, handleCompleteClick, selectFcp, setTheme + handleFileSelect, executeUpload, addJournalEntry, submitProblem, handleCompleteClick, selectFcp, setTheme, + saveWorkorderData // <-- ADDED }; }, template: ` @@ -593,6 +659,20 @@
{{ selectedWorkorder.additionalInfo || 'Keine Notiz.' }}
+