Files
netwatch/app/modules/devices/list.php
2026-02-13 11:55:18 +01:00

387 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* modules/devices/list.php
* Vollständige Geräteübersicht mit Filter
*/
// =========================
// Filter / Suche einlesen
// =========================
$search = trim($_GET['search'] ?? '');
$typeId = (int)($_GET['type_id'] ?? 0);
$locationId = (int)($_GET['location_id'] ?? 0);
$floorId = (int)($_GET['floor_id'] ?? 0);
$rackId = (int)($_GET['rack_id'] ?? 0);
// =========================
// WHERE-Clause dynamisch bauen
// =========================
$where = [];
$types = '';
$params = [];
if ($search !== '') {
$where[] = "(d.name LIKE ? OR d.serial_number LIKE ? OR dt.name LIKE ?)";
$types .= "sss";
$params[] = "%$search%";
$params[] = "%$search%";
$params[] = "%$search%";
}
if ($typeId > 0) {
$where[] = "d.device_type_id = ?";
$types .= "i";
$params[] = $typeId;
}
if ($floorId > 0) {
$where[] = "f.id = ?";
$types .= "i";
$params[] = $floorId;
}
if ($rackId > 0) {
$where[] = "d.rack_id = ?";
$types .= "i";
$params[] = $rackId;
}
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
// =========================
// Geräte laden
// =========================
$devices = $sql->get(
"
SELECT
d.id,
d.name,
d.serial_number,
d.rack_position_he,
d.rack_height_he,
d.web_config_url,
dt.name AS device_type,
dt.image_path,
f.name AS floor_name,
r.name AS rack_name,
(
SELECT COUNT(*)
FROM device_ports dp
WHERE dp.device_id = d.id
) AS port_count,
(
SELECT COUNT(*)
FROM device_port_modules dpm
JOIN device_ports dp2 ON dp2.id = dpm.device_port_id
WHERE dp2.device_id = d.id
) AS module_count,
(
SELECT COUNT(*)
FROM connections c
WHERE (c.port_a_type = 'device' AND c.port_a_id IN (
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = d.id
))
OR (c.port_b_type = 'device' AND c.port_b_id IN (
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = d.id
))
) AS connection_count
FROM devices d
JOIN device_types dt ON dt.id = d.device_type_id
LEFT JOIN racks r ON r.id = d.rack_id
LEFT JOIN floors f ON f.id = r.floor_id
$whereSql
ORDER BY f.name, r.name, d.rack_position_he, d.name
",
$types,
$params
);
// =========================
// Filter-Daten laden
// =========================
$deviceTypes = $sql->get("SELECT id, name FROM device_types ORDER BY name", "", []);
$floors = $sql->get("SELECT id, name FROM floors ORDER BY name", "", []);
$racks = $sql->get("SELECT id, name FROM racks ORDER BY name", "", []);
?>
<div class="devices-container">
<h1>Geräte</h1>
<!-- =========================
Filter-Toolbar
========================= -->
<form method="get" class="filter-form">
<input type="hidden" name="module" value="devices">
<input type="hidden" name="action" value="list">
<input type="text" name="search" placeholder="Suche nach Name oder Seriennummer…"
value="<?php echo htmlspecialchars($search); ?>" class="search-input">
<select name="type_id">
<option value="">- Alle Typen -</option>
<?php foreach ($deviceTypes as $t): ?>
<option value="<?php echo $t['id']; ?>" <?php echo $t['id'] === $typeId ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($t['name']); ?>
</option>
<?php endforeach; ?>
</select>
<select name="floor_id">
<option value="">- Alle Stockwerke -</option>
<?php foreach ($floors as $f): ?>
<option value="<?php echo $f['id']; ?>" <?php echo $f['id'] === $floorId ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($f['name']); ?>
</option>
<?php endforeach; ?>
</select>
<select name="rack_id">
<option value="">- Alle Racks -</option>
<?php foreach ($racks as $r): ?>
<option value="<?php echo $r['id']; ?>" <?php echo $r['id'] === $rackId ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($r['name']); ?>
</option>
<?php endforeach; ?>
</select>
<button type="submit" class="button">Filter</button>
<a href="?module=devices&action=list" class="button">Reset</a>
<a href="?module=devices&action=edit" class="button button-primary" style="margin-left: auto;">
+ Neues Gerät
</a>
</form>
<!-- =========================
Geräte-Liste
========================= -->
<?php if (!empty($devices)): ?>
<div class="device-stats">
<p>Gefundene Geräte: <strong><?php echo count($devices); ?></strong></p>
</div>
<table class="device-list">
<thead>
<tr>
<th>Name</th>
<th>Typ</th>
<th>Stockwerk</th>
<th>Rack</th>
<th>Position (HE)</th>
<th>Seriennummer</th>
<th>Webconfig</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<?php foreach ($devices as $d): ?>
<tr>
<td>
<strong><?php echo htmlspecialchars($d['name']); ?></strong>
</td>
<td>
<?php echo htmlspecialchars($d['device_type']); ?>
</td>
<td>
<?php echo htmlspecialchars($d['floor_name'] ?? '—'); ?>
</td>
<td>
<?php echo htmlspecialchars($d['rack_name'] ?? '—'); ?>
</td>
<td>
<?php
if ($d['rack_position_he']) {
echo $d['rack_position_he'];
if ($d['rack_height_he']) {
echo "" . ($d['rack_position_he'] + $d['rack_height_he'] - 1);
}
} else {
echo "—";
}
?>
</td>
<td>
<small><?php echo htmlspecialchars($d['serial_number'] ?? '—'); ?></small>
</td>
<td>
<?php if (!empty($d['web_config_url'])): ?>
<a href="<?php echo htmlspecialchars($d['web_config_url']); ?>" target="_blank" rel="noopener noreferrer" class="button button-small">
Webconfig
</a>
<?php else: ?>
<?php endif; ?>
</td>
<td class="actions">
<a href="?module=devices&action=edit&id=<?php echo $d['id']; ?>" class="button button-small">Bearbeiten</a>
<a href="?module=devices&action=delete&id=<?php echo (int)$d['id']; ?>" class="button button-small button-danger" onclick="return confirmDelete(event, <?php echo (int)$d['id']; ?>, <?php echo (int)$d['connection_count']; ?>, <?php echo (int)$d['port_count']; ?>, <?php echo (int)$d['module_count']; ?>)">Löschen</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<div class="empty-state">
<p>Keine Geräte gefunden.</p>
<p>
<a href="?module=devices&action=edit" class="button button-primary">
Erstes Gerät anlegen
</a>
</p>
</div>
<?php endif; ?>
</div>
<style>
.devices-container {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.filter-form {
display: flex;
gap: 10px;
margin: 20px 0;
flex-wrap: wrap;
align-items: center;
}
.filter-form input,
.filter-form select {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-family: inherit;
}
.search-input {
flex: 1;
min-width: 250px;
}
.device-stats {
background: #f0f0f0;
padding: 10px 15px;
border-radius: 4px;
margin: 15px 0;
}
.device-list {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
.device-list th {
background: #f5f5f5;
padding: 12px;
text-align: left;
border-bottom: 2px solid #ddd;
font-weight: bold;
}
.device-list td {
padding: 12px;
border-bottom: 1px solid #ddd;
}
.device-list tr:hover {
background: #f9f9f9;
}
.actions {
white-space: nowrap;
}
.button {
display: inline-block;
padding: 8px 12px;
background: #007bff;
color: white;
text-decoration: none;
border-radius: 4px;
border: none;
cursor: pointer;
font-size: 0.9em;
}
.button:hover {
background: #0056b3;
}
.button-primary {
background: #28a745;
}
.button-primary:hover {
background: #218838;
}
.button-small {
padding: 4px 8px;
font-size: 0.85em;
}
.button-danger {
background: #dc3545;
}
.button-danger:hover {
background: #c82333;
}
.empty-state {
text-align: center;
padding: 40px 20px;
background: #f9f9f9;
border: 1px solid #eee;
border-radius: 8px;
}
</style>
<script>
function confirmDelete(event, id, connectionCount, portCount, moduleCount) {
if (event && typeof event.preventDefault === 'function') {
event.preventDefault();
}
if (confirm('Dieses Gerät wirklich löschen?')) {
const hasDependencies = (connectionCount > 0) || (portCount > 0) || (moduleCount > 0);
if (hasDependencies) {
const details = [];
if (connectionCount > 0) {
details.push(connectionCount + ' Verbindungen');
}
if (portCount > 0) {
details.push(portCount + ' Ports');
}
if (moduleCount > 0) {
details.push(moduleCount + ' Port-Module');
}
const dependencyMessage = 'Es gibt abhängige Daten (' + details.join(', ') + '). Diese auch löschen?';
if (!confirm(dependencyMessage)) {
return false;
}
window.location.href = '?module=devices&action=delete&id=' + encodeURIComponent(id) + '&force=1';
return false;
}
window.location.href = '?module=devices&action=delete&id=' + encodeURIComponent(id);
return false;
}
return false;
}
</script>