This commit is contained in:
2026-02-13 11:23:28 +01:00
parent 8ee3252c51
commit 3507024bc3
3 changed files with 214 additions and 27 deletions

View File

@@ -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;
<input type="text" name="name" value="<?php echo htmlspecialchars($panel['name'] ?? ''); ?>" required>
</div>
<div class="form-group">
<label>Stockwerk</label>
<select name="floor_id" required>
<option value="">- wählen -</option>
<?php foreach ($floors as $floor): ?>
<option value="<?php echo $floor['id']; ?>" <?php echo ($panel['floor_id'] ?? 0) === $floor['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($floor['name']); ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-grid">
<div class="form-group">
<label>Location</label>
<select id="panel-location-select">
<option value="">- Location wählen -</option>
<?php foreach ($locations as $location): ?>
<option value="<?php echo $location['id']; ?>" <?php echo $selectedLocationId === $location['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($location['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label>Gebäude</label>
<select id="panel-building-select">
<option value="">- Gebäude wählen -</option>
<?php foreach ($buildings as $building): ?>
<?php $buildingLocation = $locationMap[$building['location_id']] ?? ''; ?>
<option value="<?php echo $building['id']; ?>"
data-location-id="<?php echo $building['location_id'] ?? 0; ?>"
<?php echo $selectedBuildingId === $building['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($building['name'] . ($buildingLocation ? ' · ' . $buildingLocation : '')); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label>Stockwerk</label>
<select id="panel-floor-select" name="floor_id" required>
<option value="">- Stockwerk wählen -</option>
<?php foreach ($floors as $floor): ?>
<option value="<?php echo $floor['id']; ?>"
data-building-id="<?php echo $floor['building_id'] ?? 0; ?>"
data-location-id="<?php echo $floor['location_id'] ?? 0; ?>"
data-svg-url="<?php echo htmlspecialchars($floor['svg_url']); ?>"
<?php echo $selectedFloorId === $floor['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($floor['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-grid">
@@ -114,6 +188,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
data-marker-type="patchpanel"
data-x-field="pos_x"
data-y-field="pos_y">
<img id="floor-plan-svg" class="floor-plan-svg" alt="Stockwerksplan">
<div id="floor-plan-marker" class="floor-plan-marker panel-marker"
style="--marker-width: <?php echo $markerWidth; ?>px; --marker-height: <?php echo $markerHeight; ?>px;"></div>
</div>
@@ -142,10 +217,13 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
<div class="form-group">
<label>Raum</label>
<select name="room_id" required>
<select name="room_id" id="outlet-room-select" required>
<option value="">- Raum wählen -</option>
<?php foreach ($rooms as $room): ?>
<option value="<?php echo $room['id']; ?>" <?php echo ($outlet['room_id'] ?? 0) === $room['id'] ? 'selected' : ''; ?>>
<option value="<?php echo $room['id']; ?>"
data-floor-id="<?php echo $room['floor_id'] ?? 0; ?>"
data-floor-svg-url="<?php echo htmlspecialchars($room['floor_svg_url']); ?>"
<?php echo ($outlet['room_id'] ?? 0) === $room['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($room['floor_name'] . ' / ' . $room['name']); ?>
</option>
<?php endforeach; ?>
@@ -171,6 +249,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
data-marker-type="outlet"
data-x-field="x"
data-y-field="y">
<img id="floor-plan-svg" class="floor-plan-svg" alt="Stockwerksplan">
<div id="floor-plan-marker" class="floor-plan-marker outlet-marker"
style="--marker-width: <?php echo $markerWidth; ?>px; --marker-height: <?php echo $markerHeight; ?>px;"></div>
</div>
@@ -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();
}
});
</script>