.
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user