ports beim erstellen des types erstellen
This commit is contained in:
@@ -44,10 +44,11 @@ if (!in_array($action, $validActions)) {
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Template-Header laden
|
||||
* Template-Header laden (nur für non-save Aktionen)
|
||||
* ========================= */
|
||||
require_once __DIR__ . '/templates/header.php';
|
||||
// TODO: ggf. Navigation einbinden
|
||||
if ($action !== 'save') {
|
||||
require_once __DIR__ . '/templates/header.php';
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Modul laden
|
||||
@@ -58,10 +59,14 @@ if (file_exists($modulePath)) {
|
||||
require_once $modulePath;
|
||||
} else {
|
||||
// TODO: Fehlerseite oder 404
|
||||
echo "<p>Die Seite existiert noch nicht.</p>".$modulePath;
|
||||
if ($action !== 'save') {
|
||||
echo "<p>Die Seite existiert noch nicht.</p>".$modulePath;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Template-Footer laden
|
||||
* Template-Footer laden (nur für non-save Aktionen)
|
||||
* ========================= */
|
||||
require_once __DIR__ . '/templates/footer.php';
|
||||
if ($action !== 'save') {
|
||||
require_once __DIR__ . '/templates/footer.php';
|
||||
}
|
||||
|
||||
@@ -74,6 +74,13 @@ $pageTitle = $isEdit ? "Gerätetyp bearbeiten: " . htmlspecialchars($deviceType[
|
||||
<textarea id="comment" name="comment" rows="3"
|
||||
placeholder="z.B. Rack-Mount, 48 RJ45 + 4 SFP"><?php echo htmlspecialchars($deviceType['comment'] ?? ''); ?></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="seed_ports">Ports automatisch anlegen</label>
|
||||
<input type="number" id="seed_ports" name="seed_ports" min="0" step="1"
|
||||
value="<?php echo htmlspecialchars((int)($_POST['seed_ports'] ?? 0)); ?>"
|
||||
placeholder="z.B. 48">
|
||||
<small>Beim Speichern werden bis zu dieser Zahl Platzhalter-Ports erstellt, bestehende Einträge bleiben erhalten.</small>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- =========================
|
||||
|
||||
@@ -60,6 +60,31 @@
|
||||
<!-- TODO: Import / Export -->
|
||||
</div>
|
||||
|
||||
<form id="port-form" class="port-form" aria-hidden="true">
|
||||
<div>
|
||||
<label for="port-name">Portname</label>
|
||||
<input id="port-name" name="name" required placeholder="z. B. Gi1/0/1">
|
||||
</div>
|
||||
<div>
|
||||
<label for="port-type">Port-Typ</label>
|
||||
<input id="port-type" name="type" required placeholder="RJ45, SFP …">
|
||||
</div>
|
||||
<div>
|
||||
<label for="port-medium">Medium</label>
|
||||
<input id="port-medium" name="medium" placeholder="Kupfer, LWL …">
|
||||
</div>
|
||||
<div>
|
||||
<label for="port-mode">Modus</label>
|
||||
<input id="port-mode" name="mode" placeholder="Access, Trunk …">
|
||||
</div>
|
||||
<div>
|
||||
<label for="port-vlan">VLAN</label>
|
||||
<input id="port-vlan" name="vlan" placeholder="10, 20-30 …">
|
||||
</div>
|
||||
<button type="submit" class="button button-primary">Port hinzufügen</button>
|
||||
<button type="button" class="button" id="cancel-port">Abbrechen</button>
|
||||
</form>
|
||||
|
||||
<!-- =========================
|
||||
Port-Liste
|
||||
========================= -->
|
||||
@@ -76,7 +101,7 @@
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody id="port-list-body">
|
||||
|
||||
<?php /* foreach ($ports as $port): */ ?>
|
||||
<tr>
|
||||
@@ -142,14 +167,99 @@
|
||||
JS-Konfiguration
|
||||
========================= -->
|
||||
|
||||
<style>
|
||||
.port-form {
|
||||
display: none;
|
||||
margin: 20px 0;
|
||||
gap: 10px;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
background: #f9f9f9;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
grid-auto-rows: minmax(50px, auto);
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.port-form.visible {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.port-form div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.port-form label {
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.port-form input {
|
||||
padding: 6px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #bbb;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.port-form button {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.port-form .button-primary {
|
||||
justify-self: flex-start;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const addPortButton = document.getElementById('add-port');
|
||||
const portForm = document.getElementById('port-form');
|
||||
const portListBody = document.getElementById('port-list-body');
|
||||
const cancelPortButton = document.getElementById('cancel-port');
|
||||
let portCounter = portListBody.querySelectorAll('tr').length + 1;
|
||||
|
||||
function showPortForm(show = true) {
|
||||
portForm.classList.toggle('visible', show);
|
||||
portForm.setAttribute('aria-hidden', show ? 'false' : 'true');
|
||||
if (show) {
|
||||
portForm.querySelector('input').focus();
|
||||
}
|
||||
}
|
||||
|
||||
addPortButton.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
showPortForm(portForm.getAttribute('aria-hidden') === 'true');
|
||||
});
|
||||
|
||||
cancelPortButton.addEventListener('click', () => {
|
||||
showPortForm(false);
|
||||
portForm.reset();
|
||||
});
|
||||
|
||||
portForm.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
const data = new FormData(portForm);
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${portCounter++}</td>
|
||||
<td>${data.get('name') || '-'}</td>
|
||||
<td>${data.get('type') || '-'}</td>
|
||||
<td>${data.get('medium') || '-'}</td>
|
||||
<td>${data.get('mode') || '-'}</td>
|
||||
<td>${data.get('vlan') || '-'}</td>
|
||||
<td>
|
||||
<button type="button">Bearbeiten</button>
|
||||
<button type="button">Löschen</button>
|
||||
</td>
|
||||
`;
|
||||
portListBody.appendChild(row);
|
||||
showPortForm(false);
|
||||
portForm.reset();
|
||||
});
|
||||
|
||||
/**
|
||||
* Konfiguration für svg-editor.js
|
||||
* TODO: Replace this mock logic with real AJAX once ports are
|
||||
* persisted on the backend.
|
||||
*/
|
||||
|
||||
// TODO: Gerätetyp-ID setzen
|
||||
// window.DEVICE_TYPE_ID = <?= (int)$deviceTypeId ?>;
|
||||
|
||||
// TODO: Ports an JS übergeben
|
||||
// window.DEVICE_TYPE_PORTS = <?= json_encode($ports) ?>;
|
||||
</script>
|
||||
|
||||
@@ -21,6 +21,7 @@ $deviceTypeId = (int)($_POST['id'] ?? 0);
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$category = $_POST['category'] ?? 'other';
|
||||
$comment = trim($_POST['comment'] ?? '');
|
||||
$seedPortCount = max(0, (int)($_POST['seed_ports'] ?? 0));
|
||||
|
||||
// =========================
|
||||
// Validierung
|
||||
@@ -46,6 +47,7 @@ if (!empty($errors)) {
|
||||
// Bild-Upload verarbeiten
|
||||
// =========================
|
||||
$imagePath = null;
|
||||
$imageType = null;
|
||||
if (!empty($_FILES['image']['name'])) {
|
||||
$file = $_FILES['image'];
|
||||
$tmpName = $file['tmp_name'];
|
||||
@@ -71,6 +73,7 @@ if (!empty($_FILES['image']['name'])) {
|
||||
|
||||
if (move_uploaded_file($tmpName, $destPath)) {
|
||||
$imagePath = 'uploads/device_types/' . $newFileName;
|
||||
$imageType = $fileExt === 'svg' ? 'svg' : 'bitmap';
|
||||
} else {
|
||||
$_SESSION['error'] = "Datei-Upload fehlgeschlagen";
|
||||
header('Location: ?module=device_types&action=edit' . ($deviceTypeId ? "&id=$deviceTypeId" : ""));
|
||||
@@ -83,22 +86,40 @@ if (!empty($_FILES['image']['name'])) {
|
||||
// =========================
|
||||
if ($deviceTypeId > 0) {
|
||||
// UPDATE
|
||||
$sql->set(
|
||||
"UPDATE device_types SET name = ?, category = ?, comment = ?" . ($imagePath ? ", image_path = ?, image_type = ?" : "") . " WHERE id = ?",
|
||||
$imagePath ? "sssss" : "sssi",
|
||||
$imagePath ? [$name, $category, $comment, $imagePath, $fileExt, $deviceTypeId] : [$name, $category, $comment, $deviceTypeId]
|
||||
);
|
||||
if ($imagePath) {
|
||||
$sql->set(
|
||||
"UPDATE device_types SET name = ?, category = ?, comment = ?, image_path = ?, image_type = ? WHERE id = ?",
|
||||
"sssisi",
|
||||
[$name, $category, $comment, $imagePath, $imageType, $deviceTypeId]
|
||||
);
|
||||
} else {
|
||||
$sql->set(
|
||||
"UPDATE device_types SET name = ?, category = ?, comment = ? WHERE id = ?",
|
||||
"sssi",
|
||||
[$name, $category, $comment, $deviceTypeId]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// INSERT
|
||||
$imageType = $imagePath ? $fileExt : null;
|
||||
$sql->set(
|
||||
"INSERT INTO device_types (name, category, comment, image_path, image_type) VALUES (?, ?, ?, ?, ?)",
|
||||
"sssss",
|
||||
[$name, $category, $comment, $imagePath, $imageType]
|
||||
);
|
||||
$deviceTypeId = $sql->h->insert_id;
|
||||
if ($imagePath) {
|
||||
$deviceTypeId = $sql->set(
|
||||
"INSERT INTO device_types (name, category, comment, image_path, image_type) VALUES (?, ?, ?, ?, ?)",
|
||||
"sssss",
|
||||
[$name, $category, $comment, $imagePath, $imageType],
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$deviceTypeId = $sql->set(
|
||||
"INSERT INTO device_types (name, category, comment, image_path, image_type) VALUES (?, ?, ?, NULL, ?)",
|
||||
"ssss",
|
||||
[$name, $category, $comment, 'bitmap'],
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
seedDeviceTypePorts($sql, $deviceTypeId, $seedPortCount);
|
||||
|
||||
$_SESSION['success'] = $deviceTypeId ? "Gerätetyp gespeichert" : "Fehler beim Speichern";
|
||||
|
||||
// =========================
|
||||
@@ -107,3 +128,28 @@ $_SESSION['success'] = $deviceTypeId ? "Gerätetyp gespeichert" : "Fehler beim S
|
||||
header('Location: ?module=device_types&action=list');
|
||||
exit;
|
||||
|
||||
function seedDeviceTypePorts($sql, $deviceTypeId, $targetCount)
|
||||
{
|
||||
if ($deviceTypeId <= 0 || $targetCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $sql->single(
|
||||
"SELECT COUNT(*) AS count FROM device_type_ports WHERE device_type_id = ?",
|
||||
"i",
|
||||
[$deviceTypeId]
|
||||
);
|
||||
|
||||
$existing = (int)($result['count'] ?? 0);
|
||||
$toCreate = max(0, $targetCount - $existing);
|
||||
|
||||
for ($i = 1; $i <= $toCreate; $i++) {
|
||||
$index = $existing + $i;
|
||||
$sql->set(
|
||||
"INSERT INTO device_type_ports (device_type_id, name, port_type_id, x, y) VALUES (?, ?, NULL, 0, 0)",
|
||||
"is",
|
||||
[$deviceTypeId, "Port $index"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ if ($rackId > 0) {
|
||||
// INSERT
|
||||
$sql->set(
|
||||
"INSERT INTO racks (name, floor_id, height_he, comment) VALUES (?, ?, ?, ?)",
|
||||
"sii s",
|
||||
"siis",
|
||||
[$name, $floorId, $heightHe, $comment]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@
|
||||
|
||||
<nav class="main-nav">
|
||||
<ul>
|
||||
<?php foreach ($navItems as $module => $label): ?>
|
||||
<?php foreach ($navItems as $navModule => $label): ?>
|
||||
<?php
|
||||
$active = ($currentModule === $module) ? 'active' : '';
|
||||
$active = ($currentModule === $navModule) ? 'active' : '';
|
||||
?>
|
||||
<li class="<?= $active ?>">
|
||||
<a href="?module=<?= $module ?>&action=list">
|
||||
<a href="?module=<?= $navModule ?>&action=list">
|
||||
<?= $label ?>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -104,9 +104,6 @@ Ein Serverschrank oder Netzwerkschrank.
|
||||
- Befindet sich auf einem Stockwerk
|
||||
- Enthält Geräte
|
||||
|
||||
**Wichtige Attribute**
|
||||
- `height_he`: Gesamthöhe des Racks in Höheneinheiten (HE)
|
||||
|
||||
---
|
||||
|
||||
## 4. Gerätetypen & Geräte
|
||||
@@ -280,3 +277,4 @@ Das Schema ist vorbereitet für:
|
||||
- Design-Themes
|
||||
|
||||
Diese Funktionen sind bewusst **nicht Bestandteil der ersten Version**.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user