diff --git a/app/assets/css/locations-list.css b/app/assets/css/locations-list.css new file mode 100644 index 0000000..74cc70c --- /dev/null +++ b/app/assets/css/locations-list.css @@ -0,0 +1,187 @@ +.locations-container { + padding: 20px; + max-width: 1000px; + margin: 0 auto; +} + +.locations-filter-form { + display: flex; + gap: 10px; + flex-wrap: wrap; + align-items: center; +} + +.locations-filter-add { + margin-left: auto; +} + +.search-input { + flex: 1; + min-width: 250px; +} + +.locations-list { + width: 100%; + border-collapse: collapse; + margin: 15px 0; +} + +.locations-list th { + background: #f5f5f5; + padding: 12px; + text-align: left; + border-bottom: 2px solid #ddd; + font-weight: bold; +} + +.locations-list td { + padding: 12px; + border-bottom: 1px solid #ddd; +} + +.locations-list tr:hover { + background: #f9f9f9; +} + +.actions { + white-space: nowrap; +} + +.button { + display: inline-block; + padding: 8px 12px; + background: #007bff; + color: #fff; + 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; +} + +.hierarchy-section { + padding: 20px; + max-width: 1200px; + margin: 30px auto; + border-top: 1px solid #ddd; +} + +.hierarchy-section h2 { + margin-bottom: 15px; + font-size: 1.3rem; +} + +.hierarchy-table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + border: 1px solid #d8dee5; + border-radius: 10px; + overflow: hidden; +} + +.hierarchy-table th { + background: #f3f6fa; + padding: 10px 12px; + text-align: left; + font-size: 0.9rem; + font-weight: 600; + border-bottom: 1px solid #d8dee5; +} + +.hierarchy-table td { + padding: 9px 12px; + border-bottom: 1px solid #eef2f6; + vertical-align: top; +} + +.hierarchy-row:last-child td { + border-bottom: none; +} + +.hierarchy-row--empty { + background: #fcfcfc; +} + +.hierarchy-cell { + white-space: nowrap; +} + +.hierarchy-cell--location { + background: #fbfcfe; + font-weight: 600; + min-width: 170px; +} + +.hierarchy-cell--building { + padding-left: 18px; + min-width: 180px; +} + +.hierarchy-cell--floor { + padding-left: 24px; + min-width: 190px; +} + +.hierarchy-cell--room { + padding-left: 56px; + min-width: 190px; +} + +.hierarchy-cell--empty { + background: #fafbfd; + width: 20px; +} + +.hierarchy-meta { + color: #4e5c6b; + font-size: 0.88rem; +} + +.hierarchy-meta--muted { + color: #8a94a3; +} + +.hierarchy-actions { + display: flex; + gap: 6px; + flex-wrap: wrap; +} + +.hierarchy-actions .button { + padding: 4px 10px; + font-size: 0.8rem; +} diff --git a/app/assets/js/locations-list.js b/app/assets/js/locations-list.js new file mode 100644 index 0000000..19cbc2d --- /dev/null +++ b/app/assets/js/locations-list.js @@ -0,0 +1,78 @@ +(() => { + function postDelete(url) { + return fetch(url, { + method: 'POST', + headers: { 'X-Requested-With': 'XMLHttpRequest' } + }).then((response) => response.json()); + } + + function handleLocationDelete(id) { + if (!confirm('Diesen Standort wirklich loeschen?')) { + return; + } + postDelete('?module=locations&action=delete&id=' + encodeURIComponent(id)) + .then((data) => { + if (data && data.success) { + window.location.reload(); + return; + } + alert((data && data.message) ? data.message : 'Loeschen fehlgeschlagen'); + }) + .catch(() => alert('Loeschen fehlgeschlagen')); + } + + function handleBuildingDelete() { + if (confirm('Dieses Gebaeude wirklich loeschen? Alle Stockwerke werden geloescht.')) { + alert('Loeschen noch nicht implementiert'); + } + } + + function handleFloorDelete() { + if (confirm('Dieses Stockwerk wirklich loeschen? Alle Raeume und Racks werden geloescht.')) { + alert('Loeschen noch nicht implementiert'); + } + } + + function handleRoomDelete(id) { + if (!confirm('Diesen Raum wirklich loeschen? Zugeordnete Dosen werden mitgeloescht.')) { + return; + } + postDelete('?module=rooms&action=delete&id=' + encodeURIComponent(id)) + .then((data) => { + if (data && data.success) { + window.location.reload(); + return; + } + alert((data && data.message) ? data.message : 'Loeschen fehlgeschlagen'); + }) + .catch(() => alert('Loeschen fehlgeschlagen')); + } + + function bindDeleteButtons() { + document.querySelectorAll('.js-delete-location').forEach((button) => { + button.addEventListener('click', () => { + handleLocationDelete(Number(button.dataset.locationId || 0)); + }); + }); + + document.querySelectorAll('.js-delete-building').forEach((button) => { + button.addEventListener('click', () => { + handleBuildingDelete(Number(button.dataset.buildingId || 0)); + }); + }); + + document.querySelectorAll('.js-delete-floor').forEach((button) => { + button.addEventListener('click', () => { + handleFloorDelete(Number(button.dataset.floorId || 0)); + }); + }); + + document.querySelectorAll('.js-delete-room').forEach((button) => { + button.addEventListener('click', () => { + handleRoomDelete(Number(button.dataset.roomId || 0)); + }); + }); + } + + document.addEventListener('DOMContentLoaded', bindDeleteButtons); +})(); diff --git a/app/modules/locations/list.php b/app/modules/locations/list.php index 0283425..60d44c3 100644 --- a/app/modules/locations/list.php +++ b/app/modules/locations/list.php @@ -53,7 +53,10 @@ $rooms = $sql->get( FROM rooms r LEFT JOIN network_outlets no ON no.room_id = r.id GROUP BY r.id - ORDER BY r.floor_id, r.name", + ORDER BY r.floor_id, + CASE WHEN r.number IS NULL OR r.number = '' THEN 1 ELSE 0 END, + r.number, + r.name", '', [] ); @@ -75,10 +78,13 @@ foreach ($rooms as $room) { ?>
+ + +

Standorte

-
+ @@ -87,7 +93,7 @@ foreach ($rooms as $room) { Reset - + Neuer Standort + + Neuer Standort
@@ -109,7 +115,7 @@ foreach ($rooms as $room) { Bearbeiten - Loeschen + @@ -132,7 +138,8 @@ foreach ($rooms as $room) { Standort Gebaeude - Stockwerk / Raum + Stockwerk + Raum Details Aktionen @@ -141,7 +148,7 @@ foreach ($rooms as $room) { - + ( Gebaeude) @@ -156,7 +163,7 @@ foreach ($rooms as $room) {   - + @@ -166,7 +173,7 @@ foreach ($rooms as $room) { Bearbeiten - Loeschen + + Stockwerk @@ -177,7 +184,7 @@ foreach ($rooms as $room) {     - + Ebene @@ -188,7 +195,7 @@ foreach ($rooms as $room) { Bearbeiten - Loeschen + + Raum @@ -196,6 +203,7 @@ foreach ($rooms as $room) { +       @@ -212,7 +220,7 @@ foreach ($rooms as $room) { Bearbeiten - Loeschen + @@ -220,7 +228,7 @@ foreach ($rooms as $room) {     - Keine Raeume + Keine Raeume Fuer dieses Stockwerk sind noch keine Raeume angelegt. @@ -231,8 +239,7 @@ foreach ($rooms as $room) {   -   - Keine Gebaeude + Keine Gebaeude Fuer diesen Standort sind noch keine Gebaeude vorhanden. @@ -244,233 +251,3 @@ foreach ($rooms as $room) {

Keine Standorte gefunden.

- - - -