Files
netwatch/app/modules/floor_infrastructure/edit.php
2026-02-16 11:57:24 +01:00

304 lines
14 KiB
PHP

<?php
/**
* app/modules/floor_infrastructure/edit.php
*
* Formular zum Anlegen/Bearbeiten von Patchpanels und Wandbuchsen
*/
$type = $_GET['type'] ?? 'patchpanel';
$id = (int)($_GET['id'] ?? 0);
$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, r.x, r.y, r.width, r.height, r.polygon_points,
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;
$pageTitle = $type === 'outlet' ? 'Wandbuchse bearbeiten' : 'Patchpanel bearbeiten';
if ($type === 'patchpanel' && $id > 0) {
$panel = $sql->single(
"SELECT * FROM floor_patchpanels WHERE id = ?",
"i",
[$id]
);
if ($panel) {
$pageTitle = "Patchpanel bearbeiten: " . htmlspecialchars($panel['name']);
}
}
if ($type === 'outlet' && $id > 0) {
$outlet = $sql->single(
"SELECT * FROM network_outlets WHERE id = ?",
"i",
[$id]
);
if ($outlet) {
$pageTitle = "Wandbuchse bearbeiten: " . htmlspecialchars($outlet['name']);
}
}
$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' => 20, 'height' => 5];
$defaultOutletSize = 10;
$showPanelPlacementFields = $type === 'patchpanel' && $selectedFloorId > 0;
if ($type === 'patchpanel') {
$panel['width'] = $defaultPanelSize['width'];
$panel['height'] = $defaultPanelSize['height'];
$panel['pos_x'] = $panel['pos_x'] ?? 30;
$panel['pos_y'] = $panel['pos_y'] ?? 30;
} else {
$outlet['x'] = $outlet['x'] ?? 30;
$outlet['y'] = $outlet['y'] ?? 30;
}
$markerWidth = $type === 'patchpanel' ? $panel['width'] : $defaultOutletSize;
$markerHeight = $type === 'patchpanel' ? $panel['height'] : $defaultOutletSize;
$mapPatchPanels = $sql->get(
"SELECT id, floor_id, name, pos_x, pos_y, width, height
FROM floor_patchpanels
ORDER BY floor_id, name",
"",
[]
);
$mapOutlets = $sql->get(
"SELECT o.id, r.floor_id, o.name, o.x, o.y
FROM network_outlets o
JOIN rooms r ON r.id = o.room_id
ORDER BY r.floor_id, o.name",
"",
[]
);
?>
<div class="floor-infra-edit">
<link rel="stylesheet" href="/assets/css/floor-infrastructure-edit.css">
<h1><?php echo $pageTitle; ?></h1>
<form method="post" action="?module=floor_infrastructure&action=save" class="infra-edit-form">
<input type="hidden" name="type" value="<?php echo htmlspecialchars($type); ?>">
<input type="hidden" name="id" value="<?php echo $type === 'patchpanel' ? ($panel['id'] ?? $id) : ($outlet['id'] ?? $id); ?>">
<?php if ($type === 'patchpanel'): ?>
<div class="form-group">
<label>Name</label>
<input type="text" name="name" value="<?php echo htmlspecialchars($panel['name'] ?? ''); ?>" required>
</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">
<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>
<input type="hidden" name="pos_x" value="<?php echo (int)($panel['pos_x'] ?? 30); ?>">
<input type="hidden" name="pos_y" value="<?php echo (int)($panel['pos_y'] ?? 30); ?>">
<input type="hidden" name="width" value="<?php echo (int)$panel['width']; ?>">
<input type="hidden" name="height" value="<?php echo (int)$panel['height']; ?>">
<div id="panel-placement-fields" class="form-grid" <?php echo $showPanelPlacementFields ? '' : 'hidden'; ?>>
<p class="info">Position, Breite und Höhe werden über die Karte gesetzt.</p>
</div>
<div id="panel-floor-plan-group" class="form-group" <?php echo $showPanelPlacementFields ? '' : 'hidden'; ?>>
<label>Stockwerkskarte</label>
<div class="floor-plan-block">
<div id="floor-plan-canvas" class="floor-plan-canvas"
data-marker-width="<?php echo $markerWidth; ?>"
data-marker-height="<?php echo $markerHeight; ?>"
data-marker-type="patchpanel"
data-x-field="pos_x"
data-y-field="pos_y"
data-active-id="<?php echo (int)($panel['id'] ?? 0); ?>"
data-reference-panels="<?php echo htmlspecialchars(json_encode($mapPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
data-reference-outlets="<?php echo htmlspecialchars(json_encode($mapOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
<img id="floor-plan-svg" class="floor-plan-svg" alt="Stockwerksplan">
<svg id="floor-plan-overlay" class="floor-plan-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
</div>
<p class="floor-plan-hint">Nur das aktuell bearbeitete Patchpanel ist verschiebbar. Andere Objekte werden als Referenz halbtransparent angezeigt. Neue Objekte starten bei Position 30 x 30.</p>
<p class="floor-plan-position">Koordinate: <span id="floor-plan-position"></span></p>
</div>
</div>
<div class="form-group">
<label>Port-Anzahl</label>
<input type="number" name="port_count" value="<?php echo $panel['port_count'] ?? 0; ?>" min="0">
</div>
<p id="panel-floor-missing-hint" class="info" <?php echo $showPanelPlacementFields ? 'hidden' : ''; ?>>
Position, Größe und Stockwerkskarte werden erst angezeigt, sobald ein Stockwerk ausgewählt ist.
</p>
<div class="form-group">
<label>Kommentar</label>
<textarea name="comment"><?php echo htmlspecialchars($panel['comment'] ?? ''); ?></textarea>
</div>
<p class="info">Position und Größe folgen dem Drag-&-Drop auf dem Plan, damit alle Patchpanels einheitlich bleiben.</p>
<?php else: ?>
<div class="form-group">
<label>Name</label>
<input type="text" name="name" value="<?php echo htmlspecialchars($outlet['name'] ?? ''); ?>" required>
</div>
<div class="form-group">
<label>Raum</label>
<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']; ?>"
data-floor-id="<?php echo $room['floor_id'] ?? 0; ?>"
data-floor-svg-url="<?php echo htmlspecialchars($room['floor_svg_url']); ?>"
data-room-x="<?php echo (int)($room['x'] ?? 0); ?>"
data-room-y="<?php echo (int)($room['y'] ?? 0); ?>"
data-room-width="<?php echo (int)($room['width'] ?? 0); ?>"
data-room-height="<?php echo (int)($room['height'] ?? 0); ?>"
data-room-polygon="<?php echo htmlspecialchars((string)($room['polygon_points'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>"
<?php echo ($outlet['room_id'] ?? 0) === $room['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($room['floor_name'] . ' / ' . $room['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<input type="hidden" name="x" value="<?php echo (int)($outlet['x'] ?? 30); ?>">
<input type="hidden" name="y" value="<?php echo (int)($outlet['y'] ?? 30); ?>">
<div class="form-group">
<label>Stockwerkskarte</label>
<div class="floor-plan-block">
<div id="floor-plan-canvas" class="floor-plan-canvas"
data-marker-width="<?php echo $markerWidth; ?>"
data-marker-height="<?php echo $markerHeight; ?>"
data-marker-type="outlet"
data-x-field="x"
data-y-field="y"
data-active-id="<?php echo (int)($outlet['id'] ?? 0); ?>"
data-reference-panels="<?php echo htmlspecialchars(json_encode($mapPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
data-reference-outlets="<?php echo htmlspecialchars(json_encode($mapOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
<img id="floor-plan-svg" class="floor-plan-svg" alt="Stockwerksplan">
<svg id="floor-plan-overlay" class="floor-plan-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
</div>
<p class="floor-plan-hint">Nur die aktuell bearbeitete Wandbuchse ist verschiebbar. Blau = Patchpanel, Gruen = Dosen-Referenz, Orange = gewaehlter Raum. Netzwerkdosen sind immer 10 x 10.</p>
<p class="floor-plan-position">Koordinate: <span id="floor-plan-position"></span></p>
</div>
</div>
<div class="form-group">
<label>Kommentar</label>
<textarea name="comment"><?php echo htmlspecialchars($outlet['comment'] ?? ''); ?></textarea>
</div>
<p class="info">Wandbuchsen bleiben quadratisch, ihre Position wird über die Karte festgelegt.</p>
<?php endif; ?>
<div class="form-actions">
<button type="submit" class="button button-primary">Speichern</button>
<a href="?module=floor_infrastructure&action=list" class="button">Abbrechen</a>
</div>
</form>
</div>
<?php
//TODO drag an drop auf der stockwerkskarte für die patchfelder und wandbuchsen. buchsen haben eine einheitliche größe, und sind quadratisch, patchfelder sind auch für sich einheitlich, sind rechteckig und breiter als hoch
//TODO style in css files einsortieren
?>
<script src="/assets/js/floor-infrastructure-edit.js" defer></script>