Gerätelimit drin

Dieser Commit ist enthalten in:
2025-06-11 01:13:40 +02:00
Ursprung 4b66d8b4b4
Commit a878d9b29c
9 geänderte Dateien mit 549 neuen und 19 gelöschten Zeilen

Datei anzeigen

@@ -168,18 +168,24 @@
</div>
{% endif %}
{% if license[9] > 0 %}
<div class="d-inline-block" data-bs-toggle="tooltip" title="Telefonnummern">
<div class="d-inline-block me-2" data-bs-toggle="tooltip" title="Telefonnummern">
📱 {{ license[9] }}
</div>
{% endif %}
<div class="d-inline-block" data-bs-toggle="tooltip" title="Geräte">
💻 {{ license[11] }}/{{ license[10] }}
</div>
</div>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" onclick="toggleLicenseStatus({{ license[0] }}, {{ license[5] }})">
<button class="btn btn-outline-primary" onclick="toggleLicenseStatus({{ license[0] }}, {{ license[5] }})" title="Aktivieren/Deaktivieren">
<i class="bi bi-power"></i>
</button>
<a href="/license/edit/{{ license[0] }}{% if request.args.get('show_test') %}?ref=customers-licenses&show_test=true{% endif %}" class="btn btn-outline-secondary">
<button class="btn btn-outline-info" onclick="showDeviceManagement({{ license[0] }})" title="Geräte verwalten">
<i class="bi bi-laptop"></i>
</button>
<a href="/license/edit/{{ license[0] }}{% if request.args.get('show_test') %}?ref=customers-licenses&show_test=true{% endif %}" class="btn btn-outline-secondary" title="Bearbeiten">
<i class="bi bi-pencil"></i>
</a>
</div>
@@ -253,6 +259,28 @@
</div>
</div>
<!-- Modal für Geräte-Verwaltung -->
<div class="modal fade" id="deviceManagementModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Geräte verwalten</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="deviceManagementContent">
<div class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Lädt...</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<style>
.customer-item {
transition: all 0.2s ease;
@@ -433,6 +461,11 @@ function updateLicenseView(customerId, licenses) {
}
}
// Geräte-Anzeige hinzufügen
resourcesHtml += `<div class="resource-group">
<span class="resource-icon" data-bs-toggle="tooltip" title="Geräte">💻 ${license.active_devices}/${license.device_limit}</span>
</div>`;
html += `
<tr data-license-id="${license.id}">
<td>
@@ -453,7 +486,10 @@ function updateLicenseView(customerId, licenses) {
<button class="btn btn-outline-primary" onclick="toggleLicenseStatus(${license.id}, ${license.is_active})" title="Status ändern">
<i class="bi bi-power"></i>
</button>
<button class="btn btn-outline-info" onclick="showResourceManagement(${license.id})" title="Ressourcen verwalten">
<button class="btn btn-outline-info" onclick="showDeviceManagement(${license.id})" title="Geräte verwalten">
<i class="bi bi-laptop"></i>
</button>
<button class="btn btn-outline-secondary" onclick="showResourceManagement(${license.id})" title="Ressourcen verwalten">
<i class="bi bi-gear"></i>
</button>
<a href="/license/edit/${license.id}${window.location.search ? '?ref=customers-licenses&' + window.location.search.substring(1) : ''}" class="btn btn-outline-secondary" title="Bearbeiten">
@@ -774,5 +810,124 @@ function quarantineResource(resourceId, resourceValue) {
function saveResourceChanges() {
alert('Diese Funktion wird noch implementiert');
}
// Geräte-Verwaltung anzeigen
function showDeviceManagement(licenseId) {
const modal = new bootstrap.Modal(document.getElementById('deviceManagementModal'));
modal.show();
// Lade Geräte-Daten
fetch(`/api/license/${licenseId}/devices`)
.then(response => response.json())
.then(data => {
if (data.success) {
let content = `
<div class="mb-3">
<div class="alert alert-info">
<strong>Gerätelimit:</strong> ${data.active_count} von ${data.device_limit} Geräten aktiv
</div>
</div>`;
if (data.devices.length === 0) {
content += `
<div class="text-center py-4">
<i class="bi bi-laptop text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-3">Noch keine Geräte registriert</p>
</div>`;
} else {
content += `
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Gerätename</th>
<th>Hardware-ID</th>
<th>Betriebssystem</th>
<th>Erste Registrierung</th>
<th>Letzte Aktivität</th>
<th>IP-Adresse</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>`;
data.devices.forEach(device => {
const statusBadge = device.is_active
? '<span class="badge bg-success">Aktiv</span>'
: '<span class="badge bg-secondary">Deaktiviert</span>';
const actionButton = device.is_active
? `<button class="btn btn-sm btn-danger" onclick="deactivateDevice(${licenseId}, ${device.id}, '${device.device_name}')">
<i class="bi bi-x-circle"></i> Deaktivieren
</button>`
: '<span class="text-muted">-</span>';
content += `
<tr>
<td>${device.device_name}</td>
<td><small class="text-muted">${device.hardware_id.substring(0, 12)}...</small></td>
<td>${device.operating_system}</td>
<td>${device.first_seen}</td>
<td>${device.last_seen}</td>
<td>${device.ip_address}</td>
<td>${statusBadge}</td>
<td>${actionButton}</td>
</tr>`;
});
content += `
</tbody>
</table>
</div>`;
}
document.getElementById('deviceManagementContent').innerHTML = content;
} else {
document.getElementById('deviceManagementContent').innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle"></i> ${data.message || 'Fehler beim Laden der Geräte'}
</div>`;
}
})
.catch(error => {
console.error('Error loading devices:', error);
document.getElementById('deviceManagementContent').innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle"></i> Fehler beim Laden der Geräte
</div>`;
});
}
// Gerät deaktivieren
function deactivateDevice(licenseId, deviceId, deviceName) {
if (!confirm(`Möchten Sie das Gerät "${deviceName}" wirklich deaktivieren?`)) {
return;
}
fetch(`/api/license/${licenseId}/deactivate-device/${deviceId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Aktualisiere die Geräte-Ansicht
showDeviceManagement(licenseId);
// Aktualisiere die Lizenz-Anzeige wenn möglich
if (typeof loadCustomerLicenses === 'function' && currentCustomerId) {
loadCustomerLicenses(currentCustomerId);
}
} else {
alert(data.message || 'Fehler beim Deaktivieren des Geräts');
}
})
.catch(error => {
console.error('Error deactivating device:', error);
alert('Fehler beim Deaktivieren des Geräts');
});
}
</script>
{% endblock %}