diff --git a/Layout/default/Pop/Detail.php b/Layout/default/Pop/Detail.php
index 58b3bae68..b3b12f296 100644
--- a/Layout/default/Pop/Detail.php
+++ b/Layout/default/Pop/Detail.php
@@ -686,7 +686,9 @@ if (!empty(trim($pops->vlan_ipv6)))
= $poprack['rack']['name']; ?> - Vorderseite
diff --git a/Layout/default/Pop/_rack_body.php b/Layout/default/Pop/_rack_body.php
index 5f35c4ed8..20ff5f38d 100644
--- a/Layout/default/Pop/_rack_body.php
+++ b/Layout/default/Pop/_rack_body.php
@@ -107,9 +107,9 @@ for ($i = 1; $i <= $rack_he; $i++) : ?>
}
if ($slots['width'] == "12") $width = "85%";
- else if ($slots['width'] == "6") $width = "42%";
- else if ($slots['width'] == "4") $width = "28%";
- else if ($slots['width'] == "3") $width = "21%";
+ else if ($slots['width'] == "6") $width = "42.5%";
+ else if ($slots['width'] == "4") $width = "28.33%";
+ else if ($slots['width'] == "3") $width = "21.25%";
while ($position < $slots['position']) {
@@ -118,8 +118,7 @@ for ($i = 1; $i <= $rack_he; $i++) : ?>
$calcwidth += $slots['width'];
}
- echo ' | ' . $slots['modulname'] . $extTextspan . ' | ';
-
+ echo '' . $slots['modulname'] . $extTextspan . ' | ';
$position++;
$calcwidth += $slots['width'];
}
diff --git a/Layout/default/Preorder/Index.php b/Layout/default/Preorder/Index.php
index f5939034d..7660a9dc1 100644
--- a/Layout/default/Preorder/Index.php
+++ b/Layout/default/Preorder/Index.php
@@ -100,53 +100,484 @@ $pagination_entity_name = "Vorbestellungen";
}
}
+
+ /* styles for documents */
+ .document-upload-wrapper {
+ background: #fdfdfd;
+ border: 1px solid #e9ecef;
+ border-radius: .25rem;
+ }
+ .document-dropzone {
+ border: 2px dashed #ced4da;
+ border-radius: 0.25rem;
+ padding: 1.5rem;
+ text-align: center;
+ background-color: #f8f9fa;
+ transition: all 0.3s ease;
+ cursor: pointer;
+ }
+ .document-dropzone:hover {
+ border-color: #007bff;
+ background-color: #e9ecef;
+ }
+ .document-dropzone.active {
+ border-color: #007bff;
+ border-style: solid;
+ }
+
+ .document-staging-area {
+ max-height: 250px;
+ overflow-y: auto;
+ }
+ .document-staging-item {
+ display: flex;
+ align-items: flex-start;
+ padding: 0.75rem;
+ border: 1px solid #dee2e6;
+ border-radius: 0.25rem;
+ margin-bottom: 0.5rem;
+ background-color: #fff;
+ }
+ .doc-staging-icon {
+ flex-shrink: 0;
+ width: 30px;
+ text-align: center;
+ padding-top: 0.25rem;
+ }
+ .doc-staging-details {
+ flex-grow: 1;
+ padding: 0 0.5rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ .doc-staging-filename {
+ font-size: 0.9em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ .doc-staging-filesize {
+ font-size: 0.8em;
+ }
+ .doc-staging-actions {
+ flex-shrink: 0;
+ }
+
+ .document-list-wrapper {
+ min-height: 300px;
+ }
+ .doc-spinner {
+ display: inline-block;
+ width: 3rem;
+ height: 3rem;
+ vertical-align: text-bottom;
+ border: 0.25em solid currentColor;
+ border-right-color: transparent;
+ border-radius: 50%;
+ animation: doc-spin 0.75s linear infinite;
+ color: #007bff;
+ }
+ @keyframes doc-spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+ }
+
+ .doc-row-icon i { font-size: 1.5rem; }
+ .doc-row-icon .fa-file-pdf { color: #dc3545; }
+ .doc-row-icon .fa-file-image { color: #28a745; }
+ .doc-row-icon .fa-file-word { color: #007bff; }
+ .doc-row-icon .fa-file-excel { color: #207245; }
+ .doc-row-icon .fa-file-archive { color: #ffc107; }
+ .doc-row-icon .fa-file { color: #6c757d; }
+
+ .doc-preview-modal-body img,
+ .doc-preview-modal-body embed,
+ .doc-preview-modal-body iframe {
+ max-width: 100%;
+ max-height: 75vh;
+ border: none;
+ }
+
-
+
+ initPreorderDocumentTabs();
+ });
+
diff --git a/Layout/default/Preorder/include/preorder-detail.php b/Layout/default/Preorder/include/preorder-detail.php
index 725c69d01..31849a571 100644
--- a/Layout/default/Preorder/include/preorder-detail.php
+++ b/Layout/default/Preorder/include/preorder-detail.php
@@ -22,6 +22,7 @@
History
E-Mails
+
Dokumente
@@ -110,15 +111,7 @@
-
-
- campaign->network->owner_id === "209"): ?>
+ campaign->network->owner_id, ["209", "1"])): ?>
| Verrechnet: |
@@ -1170,9 +1163,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Keine Dokumente gefunden
+ Für diese Bestellung wurden noch keine Dokumente hochgeladen.
+
+
+
+
+
+
+ | Typ |
+ Dateiname |
+ Beschreibung |
+ Aktionen |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dateien hier ablegen oder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ filename.jpg
+ 1.2 MB
+
+ Beschreibung fehlt.
+
+
+
+
+
+
+
+
+
+ |
+ |
+ filename.pdf |
+ Beschreibung... |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
-
diff --git a/Layout/default/Timerecording/Index.php b/Layout/default/Timerecording/Index.php
index e2c277573..a0ef105e5 100644
--- a/Layout/default/Timerecording/Index.php
+++ b/Layout/default/Timerecording/Index.php
@@ -149,7 +149,7 @@ $mindate = date("Y-m-d", strtotime("+ 1 Month", $closedmonth));
data-comment="= $timerecordingCategories->require_comment ?>"
data-hourday="= $timerecordingCategories->hourday ?>"
data-businesstrip="= $timerecordingCategories->businesstrip ?>"
- data-homeoffice="= ($timerecordingCategories->hourday == 1) ? 1 : 0 ?>">= $timerecordingCategories->name ?>
+ data-homeoffice="= ($timerecordingCategories->hourday == 1 && $timerecordingCategories->approval_fibu == 0) ? 1 : 0 ?>">= $timerecordingCategories->name ?>
+
diff --git a/Layout/default/TimerecordingCategories/Index.php b/Layout/default/TimerecordingCategories/Index.php
index 81014cbd4..880ae1fa0 100644
--- a/Layout/default/TimerecordingCategories/Index.php
+++ b/Layout/default/TimerecordingCategories/Index.php
@@ -41,7 +41,7 @@
| Beizeichnung |
BMD KZ |
Buchungszeitraum |
- Genehmigungspflichtig |
+ Genehmigungspf. GF/BH |
Dienstreisemöglichkeit |
Anmerkung Pflichtfeld |
Nur Buchhaltung |
@@ -66,7 +66,7 @@
= $timerecordingcategories->name ?> |
= $timerecordingcategories->short ?> |
= $timerecordingcategorieshourday[$timerecordingcategories->hourday] ?> |
- = $timerecordingcategoriesapproval[$timerecordingcategories->approval] ?> |
+ = $timerecordingcategoriesapproval[$timerecordingcategories->approval] ." / ".$timerecordingcategoriesapproval[$timerecordingcategories->approval_fibu] ?> |
= $timerecordingcategoriesbusinesstrip[$timerecordingcategories->businesstrip] ?> |
= $timerecordingcategoriesrequire_comment[$timerecordingcategories->require_comment] ?> |
= $timerecordingcategoriesrequire_only_admin[$timerecordingcategories->only_admin] ?> |
diff --git a/Layout/default/TimerecordingPermitFibu/Index.php b/Layout/default/TimerecordingPermitFibu/Index.php
new file mode 100644
index 000000000..a7e83620d
--- /dev/null
+++ b/Layout/default/TimerecordingPermitFibu/Index.php
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Datum |
+ Mitarbeiter |
+ Von |
+ Bis |
+ Summe |
+ Buchungsart |
+ Anmerkung |
+ Freigabe |
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ start;
+ if ($timerecording->timerecordingCategory->hourday == 1) {
+ $date = date("d.m.Y", $timerecording->start);
+ $datadate = date("Y-m-d", $timerecording->start);
+ $start = date("H:i", $timerecording->start);
+ $end = date("H:i", $timerecording->end);
+ $seconds = $timerecording->end - $timerecording->start;
+ $minutes = floor(($seconds % 3600) / 60);
+ $hours = floor($seconds / 3600);
+ $sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
+ $day = $daysgerm[date("w", $timerecording->start)];
+ } else if ($timerecording->timerecordingCategory->hourday == 2) {
+ $date = date("d.m.", $timerecording->start) . " - " . $daysgerm[date("w", $timerecording->end)] . " " . date("d.m.Y", $timerecording->end);
+ $datadate = date("Y-m-d", $timerecording->start);
+ $enddate = date("Y-m-d", $timerecording->end);
+ $start = "-";
+ $end = "-";
+ $day = $daysgerm[date("w", $timerecording->start)];
+ } else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
+ $date = date("d.m.Y", $timerecording->start);
+ $datadate = date("Y-m-d", $timerecording->start);
+ $start = "-";
+ $end = "-";
+ $day = $daysgerm[date("w", $timerecording->start)];
+ } else if ($timerecording->timerecordingCategory->hourday == 6) {
+ $date = date("d.m.Y", $timerecording->start);
+ $datadate = date("Y-m-d", $timerecording->start);
+ $start = date("H:i", $timerecording->start);
+ $end = date("H:i", $timerecording->end);
+ $seconds = ($timerecording->end - $timerecording->start);
+ $minutes = floor(($seconds % 3600) / 60);
+ $hours = floor($seconds / 3600);
+ $sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
+ $day = $daysgerm[date("w", $timerecording->start)];
+ $isSeconds = $isSeconds + $seconds;
+ }
+ if ($timerecording->timerecordingCategory->approval_fibu == 1 && $timerecording->approved == 0) {
+ $state = '';
+ } else if ($timerecording->timerecordingCategory->approval_fibu == 1 && $timerecording->approved == 1) {
+ $state = '';
+ }
+ $approved = 'Offen';
+ if ($timerecording->approved == 1) $approved = 'Genehmigt';
+ $completed = 'Genehmigt';
+// if ($timerecording->completed == 1) $completed = 'Genehmigt';
+ ?>
+
+ | = $state ?>= $day . " " . $date ?> |
+ = $timerecording->user->name ?> |
+ = $start ?> |
+ = $end ?> |
+ = $sum ?> |
+ = $timerecording->timerecordingCategory->name ?> |
+ = $timerecording->comment ?> |
+ = $approved ?> |
+
+ completed == 0):
+ if ($timerecording->approved == 0) : ?>
+ $timerecording->id]) ?>"
+ onclick="if(!confirm('Buchung genehmigen?')) return false;">
+ $timerecording->id]) ?>"
+ onclick="if(!confirm('Buchung wirklich ablehnen?')) return false;">
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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.' }}
+
+
Zusatzdaten
+
+
+
+
+
+
+
+
+
+
Checkliste
@@ -672,7 +752,7 @@
-
Fehlende Checklisten-Punkte:
+
Fehlende Punkte:
@@ -870,4 +950,4 @@