.
This commit is contained in:
4
NOTES.md
4
NOTES.md
@@ -1,4 +0,0 @@
|
|||||||
# Notizen
|
|
||||||
|
|
||||||
https://chatgpt.com/share/698517b9-b1e4-800e-bbd8-d207dfb326f0
|
|
||||||
|
|
||||||
@@ -71,6 +71,3 @@ if (!in_array($action, ['save', 'delete'], true)) {
|
|||||||
require_once __DIR__ . '/templates/footer.php';
|
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
|
|
||||||
@@ -5,20 +5,52 @@
|
|||||||
* Formular zum Anlegen/Bearbeiten von Patchpanels und Wandbuchsen
|
* 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';
|
$type = $_GET['type'] ?? 'patchpanel';
|
||||||
$id = (int)($_GET['id'] ?? 0);
|
$id = (int)($_GET['id'] ?? 0);
|
||||||
|
|
||||||
$floors = $sql->get("SELECT id, name FROM floors ORDER BY name", "", []);
|
$locations = $sql->get("SELECT id, name FROM locations ORDER BY name", "", []);
|
||||||
$rooms = $sql->get(
|
$buildings = $sql->get("SELECT id, name, location_id FROM buildings ORDER BY name", "", []);
|
||||||
"SELECT r.id, r.name, f.name AS floor_name
|
$floors = $sql->get(
|
||||||
FROM rooms r
|
"SELECT f.*, b.name AS building_name, b.location_id, l.name AS location_name
|
||||||
LEFT JOIN floors f ON f.id = r.floor_id
|
FROM floors f
|
||||||
ORDER BY f.name, r.name",
|
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;
|
$panel = null;
|
||||||
$outlet = null;
|
$outlet = null;
|
||||||
@@ -49,6 +81,17 @@ if ($type === 'outlet' && $id > 0) {
|
|||||||
$panel = $panel ?? [];
|
$panel = $panel ?? [];
|
||||||
$outlet = $outlet ?? [];
|
$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];
|
$defaultPanelSize = ['width' => 140, 'height' => 40];
|
||||||
$defaultOutletSize = 32;
|
$defaultOutletSize = 32;
|
||||||
|
|
||||||
@@ -74,17 +117,48 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
|
|||||||
<input type="text" name="name" value="<?php echo htmlspecialchars($panel['name'] ?? ''); ?>" required>
|
<input type="text" name="name" value="<?php echo htmlspecialchars($panel['name'] ?? ''); ?>" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<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">
|
<div class="form-group">
|
||||||
<label>Stockwerk</label>
|
<label>Stockwerk</label>
|
||||||
<select name="floor_id" required>
|
<select id="panel-floor-select" name="floor_id" required>
|
||||||
<option value="">- wählen -</option>
|
<option value="">- Stockwerk wählen -</option>
|
||||||
<?php foreach ($floors as $floor): ?>
|
<?php foreach ($floors as $floor): ?>
|
||||||
<option value="<?php echo $floor['id']; ?>" <?php echo ($panel['floor_id'] ?? 0) === $floor['id'] ? 'selected' : ''; ?>>
|
<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']); ?>
|
<?php echo htmlspecialchars($floor['name']); ?>
|
||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -114,6 +188,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
|
|||||||
data-marker-type="patchpanel"
|
data-marker-type="patchpanel"
|
||||||
data-x-field="pos_x"
|
data-x-field="pos_x"
|
||||||
data-y-field="pos_y">
|
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"
|
<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>
|
style="--marker-width: <?php echo $markerWidth; ?>px; --marker-height: <?php echo $markerHeight; ?>px;"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,10 +217,13 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Raum</label>
|
<label>Raum</label>
|
||||||
<select name="room_id" required>
|
<select name="room_id" id="outlet-room-select" required>
|
||||||
<option value="">- Raum wählen -</option>
|
<option value="">- Raum wählen -</option>
|
||||||
<?php foreach ($rooms as $room): ?>
|
<?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']); ?>
|
<?php echo htmlspecialchars($room['floor_name'] . ' / ' . $room['name']); ?>
|
||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
@@ -171,6 +249,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
|
|||||||
data-marker-type="outlet"
|
data-marker-type="outlet"
|
||||||
data-x-field="x"
|
data-x-field="x"
|
||||||
data-y-field="y">
|
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"
|
<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>
|
style="--marker-width: <?php echo $markerWidth; ?>px; --marker-height: <?php echo $markerHeight; ?>px;"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -245,6 +324,17 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
|
|||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
overflow: hidden;
|
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 {
|
.floor-plan-marker {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -253,6 +343,7 @@ $markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
|
|||||||
height: var(--marker-height, 32px);
|
height: var(--marker-height, 32px);
|
||||||
transition: left 0.1s ease, top 0.1s ease;
|
transition: left 0.1s ease, top 0.1s ease;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
.floor-plan-marker.panel-marker {
|
.floor-plan-marker.panel-marker {
|
||||||
background: rgba(13, 110, 253, 0.25);
|
background: rgba(13, 110, 253, 0.25);
|
||||||
@@ -379,5 +470,108 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
updateFromInputs();
|
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>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user