diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index 3838587..0000000 --- a/NOTES.md +++ /dev/null @@ -1,4 +0,0 @@ -# Notizen - -https://chatgpt.com/share/698517b9-b1e4-800e-bbd8-d207dfb326f0 - diff --git a/app/index.php b/app/index.php index 6e899df..9ac3a36 100644 --- a/app/index.php +++ b/app/index.php @@ -71,6 +71,3 @@ if (!in_array($action, ['save', 'delete'], true)) { require_once __DIR__ . '/templates/footer.php'; } -//TODO patchpanel bearbeiten, muss umgebaut werden: beim erstellen, wird ein panel name eingegeben, in welcher location/gebäude/stockwerk es sich befindet und vieviele ports es hat. beim editieren wird dann die stockwerk svg geladen und man kann per drag and drop das panel auf der karte an den ort ziehen wo es hingehört und speichern. Netzwerkbuchsen genauso, eigentlich sind buchsen ja nur kleine panel - -//TODO buchse <-> buchse und panel <-> panal und panel <-> buche müssen verbindbar sein, im grunde sind buchsen auch nur kleine panel \ No newline at end of file diff --git a/app/modules/floor_infrastructure/edit.php b/app/modules/floor_infrastructure/edit.php index ce42205..c45b729 100644 --- a/app/modules/floor_infrastructure/edit.php +++ b/app/modules/floor_infrastructure/edit.php @@ -5,20 +5,52 @@ * Formular zum Anlegen/Bearbeiten von Patchpanels und Wandbuchsen */ -//TODO die auswahl der stockwerke in gebäude gruppieren und gebäude in locations gruppieren - $type = $_GET['type'] ?? 'patchpanel'; $id = (int)($_GET['id'] ?? 0); -$floors = $sql->get("SELECT id, name FROM floors ORDER BY name", "", []); -$rooms = $sql->get( - "SELECT r.id, r.name, f.name AS floor_name - FROM rooms r - LEFT JOIN floors f ON f.id = r.floor_id - ORDER BY f.name, r.name", +$locations = $sql->get("SELECT id, name FROM locations ORDER BY name", "", []); +$buildings = $sql->get("SELECT id, name, location_id FROM buildings ORDER BY name", "", []); +$floors = $sql->get( + "SELECT f.*, b.name AS building_name, b.location_id, l.name AS location_name + FROM floors f + LEFT JOIN buildings b ON b.id = f.building_id + LEFT JOIN locations l ON l.id = b.location_id + ORDER BY l.name, b.name, f.level, f.name", "", [] ); +$rooms = $sql->get( + "SELECT r.id, r.name, r.floor_id, f.name AS floor_name, f.svg_path, b.id AS building_id, l.id AS location_id + FROM rooms r + LEFT JOIN floors f ON f.id = r.floor_id + LEFT JOIN buildings b ON b.id = f.building_id + LEFT JOIN locations l ON l.id = b.location_id + ORDER BY l.name, b.name, f.level, f.name, r.name", + "", + [] +); + +$locationMap = []; +foreach ($locations as $location) { + $locationMap[$location['id']] = $location['name']; +} + +foreach ($floors as &$floor) { + $paths = trim((string)($floor['svg_path'] ?? '')); + $floor['svg_url'] = $paths !== '' ? '/' . ltrim($paths, '/\\') : ''; +} +unset($floor); + +foreach ($rooms as &$room) { + $roomPath = trim((string)($room['svg_path'] ?? '')); + $room['floor_svg_url'] = $roomPath !== '' ? '/' . ltrim($roomPath, '/\\') : ''; +} +unset($room); + +$floorIndex = []; +foreach ($floors as $floor) { + $floorIndex[$floor['id']] = $floor; +} $panel = null; $outlet = null; @@ -49,6 +81,17 @@ if ($type === 'outlet' && $id > 0) { $panel = $panel ?? []; $outlet = $outlet ?? []; +$selectedLocationId = 0; +$selectedBuildingId = 0; +$selectedFloorId = 0; +if ($type === 'patchpanel') { + $selectedFloorId = (int)($panel['floor_id'] ?? 0); + if ($selectedFloorId && isset($floorIndex[$selectedFloorId])) { + $selectedBuildingId = (int)($floorIndex[$selectedFloorId]['building_id'] ?? 0); + $selectedLocationId = (int)($floorIndex[$selectedFloorId]['location_id'] ?? 0); + } +} + $defaultPanelSize = ['width' => 140, 'height' => 40]; $defaultOutletSize = 32; @@ -74,16 +117,47 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize; -
- - +
+
+ + +
+
+ + +
+
+ + +
@@ -114,6 +188,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize; data-marker-type="patchpanel" data-x-field="pos_x" data-y-field="pos_y"> + Stockwerksplan
@@ -142,10 +217,13 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
- - @@ -171,6 +249,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize; data-marker-type="outlet" data-x-field="x" data-y-field="y"> + Stockwerksplan
@@ -245,6 +324,17 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize; cursor: crosshair; overflow: hidden; } +.floor-plan-svg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: contain; + pointer-events: none; + z-index: 0; + opacity: 0.75; + border-radius: 6px; +} .floor-plan-marker { position: absolute; top: 0; @@ -253,6 +343,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize; height: var(--marker-height, 32px); transition: left 0.1s ease, top 0.1s ease; touch-action: none; + z-index: 2; } .floor-plan-marker.panel-marker { background: rgba(13, 110, 253, 0.25); @@ -379,5 +470,108 @@ document.addEventListener('DOMContentLoaded', () => { window.addEventListener('resize', () => { updateFromInputs(); }); + + const panelLocationSelect = document.getElementById('panel-location-select'); + const panelBuildingSelect = document.getElementById('panel-building-select'); + const panelFloorSelect = document.getElementById('panel-floor-select'); + const outletRoomSelect = document.getElementById('outlet-room-select'); + const floorPlanSvg = document.getElementById('floor-plan-svg'); + + const buildingOptions = panelBuildingSelect ? Array.from(panelBuildingSelect.options).filter((option) => option.value !== '') : []; + const floorOptions = panelFloorSelect ? Array.from(panelFloorSelect.options).filter((option) => option.value !== '') : []; + + const updateFloorPlanImage = () => { + if (!floorPlanSvg) { + return; + } + + const floorOption = panelFloorSelect?.selectedOptions?.[0]; + const roomOption = outletRoomSelect?.selectedOptions?.[0]; + const svgUrl = floorOption?.dataset?.svgUrl || roomOption?.dataset?.floorSvgUrl || ''; + + if (svgUrl) { + floorPlanSvg.src = svgUrl; + } else { + floorPlanSvg.removeAttribute('src'); + } + }; + + const filterFloorOptions = () => { + if (!panelFloorSelect) { + return; + } + const buildingValue = panelBuildingSelect?.value || ''; + let firstMatch = ''; + floorOptions.forEach((option) => { + const matches = !buildingValue || option.dataset.buildingId === buildingValue; + option.hidden = !matches; + option.disabled = !matches; + if (matches && !firstMatch) { + firstMatch = option.value; + } + }); + + const selectedOption = panelFloorSelect.querySelector(`option[value="${panelFloorSelect.value}"]`); + const isSelectedHidden = selectedOption ? selectedOption.hidden : true; + if (buildingValue && (!panelFloorSelect.value || isSelectedHidden) && firstMatch) { + panelFloorSelect.value = firstMatch; + } + + updateFloorPlanImage(); + }; + + const filterBuildingOptions = () => { + if (!panelBuildingSelect) { + return; + } + const locationValue = panelLocationSelect?.value || ''; + let firstMatch = ''; + buildingOptions.forEach((option) => { + const matches = !locationValue || option.dataset.locationId === locationValue; + option.hidden = !matches; + option.disabled = !matches; + if (matches && !firstMatch) { + firstMatch = option.value; + } + }); + + const selectedOption = panelBuildingSelect.querySelector(`option[value="${panelBuildingSelect.value}"]`); + const isSelectedHidden = selectedOption ? selectedOption.hidden : true; + if (locationValue && (!panelBuildingSelect.value || isSelectedHidden) && firstMatch) { + panelBuildingSelect.value = firstMatch; + } + }; + + if (panelLocationSelect) { + panelLocationSelect.addEventListener('change', () => { + filterBuildingOptions(); + filterFloorOptions(); + }); + } + + if (panelBuildingSelect) { + panelBuildingSelect.addEventListener('change', () => { + filterFloorOptions(); + }); + } + + if (panelFloorSelect) { + panelFloorSelect.addEventListener('change', () => { + updateFloorPlanImage(); + }); + } + + if (outletRoomSelect) { + outletRoomSelect.addEventListener('change', () => { + updateFloorPlanImage(); + }); + } + + if (panelLocationSelect) { + filterBuildingOptions(); + filterFloorOptions(); + } else { + updateFloorPlanImage(); + } });