infrastruktur karte
This commit is contained in:
@@ -20,7 +20,8 @@ $floors = $sql->get(
|
||||
[]
|
||||
);
|
||||
$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
|
||||
"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
|
||||
@@ -92,13 +93,13 @@ if ($type === 'patchpanel') {
|
||||
}
|
||||
}
|
||||
|
||||
$defaultPanelSize = ['width' => 140, 'height' => 40];
|
||||
$defaultPanelSize = ['width' => 20, 'height' => 5];
|
||||
$defaultOutletSize = 10;
|
||||
$showPanelPlacementFields = $type === 'patchpanel' && $selectedFloorId > 0;
|
||||
|
||||
if ($type === 'patchpanel') {
|
||||
$panel['width'] = $panel['width'] ?? $defaultPanelSize['width'];
|
||||
$panel['height'] = $panel['height'] ?? $defaultPanelSize['height'];
|
||||
$panel['width'] = $defaultPanelSize['width'];
|
||||
$panel['height'] = $defaultPanelSize['height'];
|
||||
$panel['pos_x'] = $panel['pos_x'] ?? 30;
|
||||
$panel['pos_y'] = $panel['pos_y'] ?? 30;
|
||||
} else {
|
||||
@@ -127,6 +128,7 @@ $mapOutlets = $sql->get(
|
||||
?>
|
||||
|
||||
<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">
|
||||
@@ -204,8 +206,7 @@ $mapOutlets = $sql->get(
|
||||
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">
|
||||
<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>
|
||||
<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>
|
||||
@@ -242,6 +243,11 @@ $mapOutlets = $sql->get(
|
||||
<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>
|
||||
@@ -265,10 +271,9 @@ $mapOutlets = $sql->get(
|
||||
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">
|
||||
<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>
|
||||
<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. Andere Objekte werden als Referenz halbtransparent angezeigt. Netzwerkdosen sind immer 10 x 10.</p>
|
||||
<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>
|
||||
@@ -292,119 +297,7 @@ $mapOutlets = $sql->get(
|
||||
//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
|
||||
?>
|
||||
<style>
|
||||
.floor-infra-edit {
|
||||
padding: 25px;
|
||||
max-width: 700px;
|
||||
}
|
||||
.infra-edit-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
.info {
|
||||
font-size: 0.9em;
|
||||
color: #555;
|
||||
}
|
||||
.floor-plan-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.floor-plan-canvas {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 260px;
|
||||
border: 1px solid #d4d4d4;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
background-image:
|
||||
linear-gradient(90deg, rgba(0, 0, 0, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(rgba(0, 0, 0, 0.05) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
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;
|
||||
left: 0;
|
||||
width: var(--marker-width, 32px);
|
||||
height: var(--marker-height, 32px);
|
||||
transition: left 0.1s ease, top 0.1s ease;
|
||||
touch-action: none;
|
||||
z-index: 2;
|
||||
}
|
||||
.floor-plan-marker.is-active {
|
||||
cursor: move;
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8), 0 0 0 4px rgba(13, 110, 253, 0.35);
|
||||
}
|
||||
.floor-plan-marker.panel-marker {
|
||||
background: rgba(13, 110, 253, 0.25);
|
||||
border: 2px solid #0d6efd;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.floor-plan-marker.outlet-marker {
|
||||
background: rgba(25, 135, 84, 0.25);
|
||||
border: 2px solid #198754;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.floor-plan-reference {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
opacity: 0.35;
|
||||
z-index: 1;
|
||||
}
|
||||
.floor-plan-reference.panel-marker {
|
||||
background: rgba(13, 110, 253, 0.22);
|
||||
border: 2px solid rgba(13, 110, 253, 0.7);
|
||||
border-radius: 6px;
|
||||
}
|
||||
.floor-plan-reference.outlet-marker {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: rgba(25, 135, 84, 0.22);
|
||||
border: 2px solid rgba(25, 135, 84, 0.7);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.floor-plan-hint {
|
||||
font-size: 0.85em;
|
||||
color: #444;
|
||||
margin: 0;
|
||||
}
|
||||
.floor-plan-position {
|
||||
margin: 0;
|
||||
font-size: 0.85em;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="/assets/js/floor-infrastructure-edit.js" defer></script>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
/**
|
||||
* app/modules/floor_infrastructure/list.php
|
||||
*
|
||||
* Übersicht über Patchpanels und Netzwerkbuchsen auf Stockwerken
|
||||
* Uebersicht ueber Patchpanels und Netzwerkbuchsen auf Stockwerken.
|
||||
*/
|
||||
|
||||
$floorId = (int)($_GET['floor_id'] ?? 0);
|
||||
|
||||
$floors = $sql->get("SELECT id, name, svg_path FROM floors ORDER BY name", "", []);
|
||||
$floors = $sql->get(
|
||||
"SELECT id, name, svg_path
|
||||
FROM floors
|
||||
ORDER BY name",
|
||||
"",
|
||||
[]
|
||||
);
|
||||
|
||||
$where = '';
|
||||
$types = '';
|
||||
@@ -15,7 +21,7 @@ $params = [];
|
||||
|
||||
if ($floorId > 0) {
|
||||
$where = "WHERE p.floor_id = ?";
|
||||
$types = "i";
|
||||
$types = 'i';
|
||||
$params[] = $floorId;
|
||||
}
|
||||
|
||||
@@ -30,10 +36,15 @@ $patchPanels = $sql->get(
|
||||
);
|
||||
|
||||
$networkOutlets = $sql->get(
|
||||
"SELECT o.*, r.name AS room_name, f.name AS floor_name, f.id AS floor_id
|
||||
"SELECT o.id, o.room_id, o.name, o.x, o.y, o.comment,
|
||||
r.name AS room_name, r.number AS room_number,
|
||||
f.name AS floor_name, f.id AS floor_id,
|
||||
GROUP_CONCAT(nop.name ORDER BY nop.name SEPARATOR ', ') AS port_names
|
||||
FROM network_outlets o
|
||||
LEFT JOIN rooms r ON r.id = o.room_id
|
||||
LEFT JOIN floors f ON f.id = r.floor_id
|
||||
LEFT JOIN network_outlet_ports nop ON nop.outlet_id = o.id
|
||||
GROUP BY o.id
|
||||
ORDER BY f.name, r.name, o.name",
|
||||
"",
|
||||
[]
|
||||
@@ -50,81 +61,101 @@ foreach ($floors as $floor) {
|
||||
];
|
||||
}
|
||||
|
||||
$editorFloorId = $floorId;
|
||||
if ($editorFloorId <= 0) {
|
||||
foreach ($floorMap as $candidate) {
|
||||
if ($candidate['svg_url'] !== '') {
|
||||
$editorFloorId = (int)$candidate['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$editorFloor = $floorMap[$editorFloorId] ?? null;
|
||||
$editorFloor = ($floorId > 0 && isset($floorMap[$floorId])) ? $floorMap[$floorId] : null;
|
||||
$editorPatchPanels = [];
|
||||
$editorOutlets = [];
|
||||
|
||||
if ($editorFloorId > 0) {
|
||||
if ($editorFloor) {
|
||||
foreach ($patchPanels as $panel) {
|
||||
if ((int)$panel['floor_id'] === $editorFloorId) {
|
||||
$editorPatchPanels[] = [
|
||||
'id' => (int)$panel['id'],
|
||||
'name' => (string)$panel['name'],
|
||||
'floor_id' => (int)$panel['floor_id'],
|
||||
'x' => (int)$panel['pos_x'],
|
||||
'y' => (int)$panel['pos_y'],
|
||||
'width' => max(1, (int)$panel['width']),
|
||||
'height' => max(1, (int)$panel['height']),
|
||||
'port_count' => (int)$panel['port_count'],
|
||||
'comment' => (string)($panel['comment'] ?? '')
|
||||
];
|
||||
if ((int)$panel['floor_id'] !== $floorId) {
|
||||
continue;
|
||||
}
|
||||
$editorPatchPanels[] = [
|
||||
'id' => (int)$panel['id'],
|
||||
'name' => (string)$panel['name'],
|
||||
'x' => (int)$panel['pos_x'],
|
||||
'y' => (int)$panel['pos_y'],
|
||||
'width' => max(1, (int)$panel['width']),
|
||||
'height' => max(1, (int)$panel['height']),
|
||||
'port_count' => (int)$panel['port_count'],
|
||||
'comment' => (string)($panel['comment'] ?? '')
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($networkOutlets as $outlet) {
|
||||
if ((int)$outlet['floor_id'] === $editorFloorId) {
|
||||
$editorOutlets[] = [
|
||||
'id' => (int)$outlet['id'],
|
||||
'name' => (string)$outlet['name'],
|
||||
'room_id' => (int)$outlet['room_id'],
|
||||
'x' => (int)$outlet['x'],
|
||||
'y' => (int)$outlet['y'],
|
||||
'comment' => (string)($outlet['comment'] ?? '')
|
||||
];
|
||||
if ((int)$outlet['floor_id'] !== $floorId) {
|
||||
continue;
|
||||
}
|
||||
$editorOutlets[] = [
|
||||
'id' => (int)$outlet['id'],
|
||||
'name' => (string)$outlet['name'],
|
||||
'x' => (int)$outlet['x'],
|
||||
'y' => (int)$outlet['y'],
|
||||
'room_name' => (string)($outlet['room_name'] ?? ''),
|
||||
'room_number' => (string)($outlet['room_number'] ?? ''),
|
||||
'port_names' => (string)($outlet['port_names'] ?? ''),
|
||||
'comment' => (string)($outlet['comment'] ?? '')
|
||||
];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="floor-infra">
|
||||
<link rel="stylesheet" href="/assets/css/floor-infrastructure-list.css">
|
||||
<script src="/assets/js/floor-infrastructure-list.js" defer></script>
|
||||
|
||||
<h1>Stockwerksinfrastruktur</h1>
|
||||
|
||||
<div class="toolbar">
|
||||
<a href="?module=floor_infrastructure&action=edit&type=patchpanel" class="button button-primary">
|
||||
+ Patchpanel hinzufügen
|
||||
+ Patchpanel hinzufuegen
|
||||
</a>
|
||||
<a href="?module=floor_infrastructure&action=edit&type=outlet" class="button">
|
||||
+ Wandbuchse hinzufügen
|
||||
+ Wandbuchse hinzufuegen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<form method="get" class="filter-form">
|
||||
<form method="get" class="filter-form" id="infra-filter-form">
|
||||
<input type="hidden" name="module" value="floor_infrastructure">
|
||||
<input type="hidden" name="action" value="list">
|
||||
|
||||
<select name="floor_id">
|
||||
<option value="">- Alle Stockwerke -</option>
|
||||
<select name="floor_id" id="infra-floor-select">
|
||||
<option value="">- Stockwerk waehlen -</option>
|
||||
<?php foreach ($floors as $floor): ?>
|
||||
<option value="<?php echo $floor['id']; ?>" <?php echo $floor['id'] === $floorId ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($floor['name']); ?>
|
||||
<option value="<?php echo (int)$floor['id']; ?>" <?php echo ((int)$floor['id'] === $floorId) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars((string)$floor['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
|
||||
<button class="button">Filter</button>
|
||||
<a href="?module=floor_infrastructure&action=list" class="button">Zurücksetzen</a>
|
||||
<button class="button" type="submit">Filter</button>
|
||||
<a href="?module=floor_infrastructure&action=list" class="button">Zuruecksetzen</a>
|
||||
</form>
|
||||
|
||||
<section class="infra-plan">
|
||||
<h2>Stockwerkskarte</h2>
|
||||
<?php if ($floorId <= 0): ?>
|
||||
<p class="empty-state">Bitte ein Stockwerk auswaehlen, um die Karte anzuzeigen.</p>
|
||||
<?php elseif (!$editorFloor): ?>
|
||||
<p class="empty-state">Gewaehltes Stockwerk wurde nicht gefunden.</p>
|
||||
<?php elseif (($editorFloor['svg_url'] ?? '') === ''): ?>
|
||||
<p class="empty-state">Das gewaehlte Stockwerk hat keinen SVG-Plan hinterlegt.</p>
|
||||
<?php else: ?>
|
||||
<p>
|
||||
Read-only Vorschau fuer <strong><?php echo htmlspecialchars((string)$editorFloor['name']); ?></strong>.
|
||||
Alle Objekte werden angezeigt; Hover zeigt Details.
|
||||
</p>
|
||||
<div id="infra-floor-canvas"
|
||||
class="infra-floor-canvas"
|
||||
data-patchpanels="<?php echo htmlspecialchars(json_encode($editorPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
|
||||
data-outlets="<?php echo htmlspecialchars(json_encode($editorOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<img src="<?php echo htmlspecialchars((string)$editorFloor['svg_url']); ?>" class="infra-floor-svg" alt="Stockwerksplan">
|
||||
<svg id="infra-floor-overlay" class="infra-floor-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
|
||||
</div>
|
||||
<p class="floor-plan-hint">Blau: Patchpanel | Gruen: Wandbuchse. Hover zeigt Name, Raum und Ports (Browser-Tooltip).</p>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="infra-section">
|
||||
<h2>Patchpanels</h2>
|
||||
<?php if (!empty($patchPanels)): ?>
|
||||
@@ -134,7 +165,7 @@ if ($editorFloorId > 0) {
|
||||
<th>Name</th>
|
||||
<th>Stockwerk</th>
|
||||
<th>Position</th>
|
||||
<th>Größe</th>
|
||||
<th>Groesse</th>
|
||||
<th>Ports</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
@@ -142,13 +173,13 @@ if ($editorFloorId > 0) {
|
||||
<tbody>
|
||||
<?php foreach ($patchPanels as $panel): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($panel['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($panel['floor_name'] ?? '-'); ?></td>
|
||||
<td><?php echo $panel['pos_x'] . ' x ' . $panel['pos_y']; ?></td>
|
||||
<td><?php echo $panel['width'] . ' x ' . $panel['height']; ?></td>
|
||||
<td><?php echo $panel['port_count']; ?></td>
|
||||
<td><?php echo htmlspecialchars((string)$panel['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)($panel['floor_name'] ?? '-')); ?></td>
|
||||
<td><?php echo (int)$panel['pos_x'] . ' x ' . (int)$panel['pos_y']; ?></td>
|
||||
<td><?php echo (int)$panel['width'] . ' x ' . (int)$panel['height']; ?></td>
|
||||
<td><?php echo (int)$panel['port_count']; ?></td>
|
||||
<td class="actions">
|
||||
<a href="?module=floor_infrastructure&action=edit&type=patchpanel&id=<?php echo $panel['id']; ?>" class="button button-small">Bearbeiten</a>
|
||||
<a href="?module=floor_infrastructure&action=edit&type=patchpanel&id=<?php echo (int)$panel['id']; ?>" class="button button-small">Bearbeiten</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@@ -169,6 +200,7 @@ if ($editorFloorId > 0) {
|
||||
<th>Stockwerk</th>
|
||||
<th>Raum</th>
|
||||
<th>Koordinaten</th>
|
||||
<th>Ports</th>
|
||||
<th>Kommentar</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
@@ -176,13 +208,23 @@ if ($editorFloorId > 0) {
|
||||
<tbody>
|
||||
<?php foreach ($networkOutlets as $outlet): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($outlet['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($outlet['floor_name'] ?? '-'); ?></td>
|
||||
<td><?php echo htmlspecialchars($outlet['room_name'] ?? '-'); ?></td>
|
||||
<td><?php echo $outlet['x'] . ' x ' . $outlet['y']; ?></td>
|
||||
<td><?php echo htmlspecialchars($outlet['comment']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)$outlet['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)($outlet['floor_name'] ?? '-')); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$roomLabel = (string)($outlet['room_name'] ?? '-');
|
||||
$roomNumber = trim((string)($outlet['room_number'] ?? ''));
|
||||
if ($roomNumber !== '') {
|
||||
$roomLabel .= ' (' . $roomNumber . ')';
|
||||
}
|
||||
echo htmlspecialchars($roomLabel);
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo (int)$outlet['x'] . ' x ' . (int)$outlet['y']; ?></td>
|
||||
<td><?php echo htmlspecialchars((string)($outlet['port_names'] ?? '-')); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)($outlet['comment'] ?? '')); ?></td>
|
||||
<td class="actions">
|
||||
<a href="?module=floor_infrastructure&action=edit&type=outlet&id=<?php echo $outlet['id']; ?>" class="button button-small">Bearbeiten</a>
|
||||
<a href="?module=floor_infrastructure&action=edit&type=outlet&id=<?php echo (int)$outlet['id']; ?>" class="button button-small">Bearbeiten</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@@ -192,154 +234,4 @@ if ($editorFloorId > 0) {
|
||||
<p class="empty-state">Noch keine Wandbuchsen angelegt.</p>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="infra-plan">
|
||||
<h2>Stockwerksplan-Verortung</h2>
|
||||
<?php if (!$editorFloor): ?>
|
||||
<p class="empty-state">Kein Stockwerk für die Planansicht verfügbar.</p>
|
||||
<?php elseif (($editorFloor['svg_url'] ?? '') === ''): ?>
|
||||
<p class="empty-state">Das gewählte Stockwerk hat noch keinen SVG-Plan hinterlegt.</p>
|
||||
<?php else: ?>
|
||||
<p>Vorschau für <strong><?php echo htmlspecialchars($editorFloor['name']); ?></strong>. Positionen bearbeitest du über den jeweiligen „Bearbeiten“-Button.</p>
|
||||
<div id="infra-floor-canvas"
|
||||
class="infra-floor-canvas"
|
||||
data-save-url="?module=floor_infrastructure&action=save"
|
||||
data-floor-id="<?php echo (int)$editorFloor['id']; ?>">
|
||||
<img src="<?php echo htmlspecialchars($editorFloor['svg_url']); ?>" class="infra-floor-svg" alt="Stockwerksplan">
|
||||
</div>
|
||||
<p class="floor-plan-hint">Patchpanels: blau, Wandbuchsen: grün. In dieser Ansicht sind Marker nicht verschiebbar.</p>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.floor-infra {
|
||||
padding: 25px;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.filter-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.filter-form select {
|
||||
padding: 8px 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.infra-section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.infra-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.infra-table th,
|
||||
.infra-table td {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.infra-plan {
|
||||
padding: 15px;
|
||||
background: #f7f7f7;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.infra-floor-canvas {
|
||||
position: relative;
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
min-height: 420px;
|
||||
border: 1px solid #d4d4d4;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
.infra-floor-svg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
pointer-events: none;
|
||||
opacity: 0.85;
|
||||
}
|
||||
.infra-marker {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
user-select: none;
|
||||
touch-action: none;
|
||||
cursor: default;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
.infra-marker.patchpanel {
|
||||
background: rgba(13, 110, 253, 0.25);
|
||||
border: 2px solid #0d6efd;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.infra-marker.outlet {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: rgba(25, 135, 84, 0.25);
|
||||
border: 2px solid #198754;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.floor-plan-hint {
|
||||
margin: 8px 0 0;
|
||||
font-size: 0.85em;
|
||||
color: #444;
|
||||
}
|
||||
.empty-state {
|
||||
padding: 20px;
|
||||
background: #fafafa;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.actions .button-small {
|
||||
margin-right: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php if ($editorFloor && ($editorFloor['svg_url'] ?? '') !== ''): ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const canvas = document.getElementById('infra-floor-canvas');
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const outletSize = 10;
|
||||
const patchPanels = <?php echo json_encode($editorPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
const outlets = <?php echo json_encode($editorOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
|
||||
const createMarker = (entry, type) => {
|
||||
const marker = document.createElement('div');
|
||||
marker.className = `infra-marker ${type}`;
|
||||
marker.dataset.id = String(entry.id);
|
||||
marker.dataset.type = type;
|
||||
marker.title = entry.name || '';
|
||||
|
||||
if (type === 'patchpanel') {
|
||||
marker.style.width = `${entry.width}px`;
|
||||
marker.style.height = `${entry.height}px`;
|
||||
}
|
||||
|
||||
marker.style.left = `${entry.x}px`;
|
||||
marker.style.top = `${entry.y}px`;
|
||||
canvas.appendChild(marker);
|
||||
};
|
||||
|
||||
patchPanels.forEach((entry) => createMarker(entry, 'patchpanel'));
|
||||
outlets.forEach((entry) => createMarker(entry, 'outlet'));
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -9,22 +9,18 @@ $type = $_POST['type'] ?? '';
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
|
||||
if ($type === 'patchpanel') {
|
||||
$fixedPanelWidth = 20;
|
||||
$fixedPanelHeight = 5;
|
||||
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$floorId = (int)($_POST['floor_id'] ?? 0);
|
||||
$posX = (int)($_POST['pos_x'] ?? 0);
|
||||
$posY = (int)($_POST['pos_y'] ?? 0);
|
||||
$width = (int)($_POST['width'] ?? 0);
|
||||
$height = (int)($_POST['height'] ?? 0);
|
||||
$width = $fixedPanelWidth;
|
||||
$height = $fixedPanelHeight;
|
||||
$portCount = (int)($_POST['port_count'] ?? 0);
|
||||
$comment = trim($_POST['comment'] ?? '');
|
||||
|
||||
if ($width <= 0) {
|
||||
$width = 140;
|
||||
}
|
||||
if ($height <= 0) {
|
||||
$height = 40;
|
||||
}
|
||||
|
||||
if ($id > 0) {
|
||||
$sql->set(
|
||||
"UPDATE floor_patchpanels SET name = ?, floor_id = ?, pos_x = ?, pos_y = ?, width = ?, height = ?, port_count = ?, comment = ? WHERE id = ?",
|
||||
|
||||
Reference in New Issue
Block a user