Zulassen von Anonymen RFID updates verlinkung der UUID wenn spieler angelegt wurde

This commit is contained in:
2025-09-11 16:33:22 +02:00
parent d2a1bb16ea
commit 28616b3b0c
14 changed files with 2676 additions and 241 deletions

View File

@@ -3,14 +3,14 @@ let currentDataType = null;
let currentData = [];
// Beim Laden der Seite
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
checkAuth();
loadStatistics();
// Add cookie settings button functionality
const cookieSettingsBtn = document.getElementById('cookie-settings-footer');
if (cookieSettingsBtn) {
cookieSettingsBtn.addEventListener('click', function() {
cookieSettingsBtn.addEventListener('click', function () {
if (window.cookieConsent) {
window.cookieConsent.resetConsent();
}
@@ -23,9 +23,9 @@ document.addEventListener('DOMContentLoaded', function() {
function setupEventListeners() {
// Logout Button
document.getElementById('logoutBtn').addEventListener('click', logout);
// Generator Button
document.getElementById('generatorBtn').addEventListener('click', function() {
document.getElementById('generatorBtn').addEventListener('click', function () {
window.location.href = '/generator';
});
@@ -48,7 +48,7 @@ async function checkAuth() {
try {
const response = await fetch('/api/v1/web/check-session');
const result = await response.json();
if (!result.success) {
window.location.href = '/adminlogin.html';
return;
@@ -56,7 +56,7 @@ async function checkAuth() {
currentUser = result.user;
document.getElementById('username').textContent = currentUser.username;
const accessBadge = document.getElementById('accessBadge');
accessBadge.textContent = `Level ${currentUser.access_level}`;
accessBadge.className = `access-badge level-${currentUser.access_level}`;
@@ -86,7 +86,7 @@ async function loadStatistics() {
try {
const response = await fetch('/api/v1/admin/stats');
const stats = await response.json();
if (stats.success) {
document.getElementById('totalPlayers').textContent = stats.data.players || 0;
document.getElementById('totalRuns').textContent = stats.data.runs || 0;
@@ -102,16 +102,16 @@ async function loadPageStatistics() {
try {
const response = await fetch('/api/v1/admin/page-stats');
const result = await response.json();
if (result.success) {
const data = result.data;
// Display page view statistics
displayPageStats('todayStats', data.today);
displayPageStats('weekStats', data.week);
displayPageStats('monthStats', data.month);
displayPageStats('totalStats', data.total);
// Display link statistics
if (data.linkStats) {
document.getElementById('totalPlayersCount').textContent = data.linkStats.total_players || 0;
@@ -130,16 +130,16 @@ async function loadPageStatistics() {
function displayPageStats(containerId, stats) {
const container = document.getElementById(containerId);
if (!stats || stats.length === 0) {
container.innerHTML = '<div style="color: #6c757d;">0</div>';
return;
}
// Find main page visits
const mainPageStat = stats.find(stat => stat.page === 'main_page_visit');
const count = mainPageStat ? mainPageStat.count : 0;
container.innerHTML = `<div style="font-size: 1.5em; font-weight: bold; color: #00d4ff;">${count}</div>`;
}
@@ -154,7 +154,7 @@ function getPageDisplayName(page) {
'license_generator': '🔧 Lizenzgenerator',
'reset_password': '🔑 Passwort Reset'
};
return pageNames[page] || page;
}
@@ -204,7 +204,7 @@ async function loadPlayers() {
try {
const response = await fetch('/api/v1/admin/players');
const result = await response.json();
if (result.success) {
currentData = result.data;
displayPlayersTable(result.data);
@@ -221,7 +221,7 @@ async function loadRuns() {
try {
const response = await fetch('/api/v1/admin/runs');
const result = await response.json();
if (result.success) {
currentData = result.data;
displayRunsTable(result.data);
@@ -238,7 +238,7 @@ async function loadLocations() {
try {
const response = await fetch('/api/v1/admin/locations');
const result = await response.json();
if (result.success) {
currentData = result.data;
displayLocationsTable(result.data);
@@ -255,7 +255,7 @@ async function loadAdminUsers() {
try {
const response = await fetch('/api/v1/admin/adminusers');
const result = await response.json();
if (result.success) {
currentData = result.data;
displayAdminUsersTable(result.data);
@@ -271,7 +271,7 @@ async function loadAdminUsers() {
function displayPlayersTable(players) {
let html = '<div class="table-container"><table class="data-table">';
html += '<thead><tr><th>ID</th><th>Name</th><th>RFID UID</th><th>Supabase User</th><th>Registriert</th><th>Aktionen</th></tr></thead><tbody>';
players.forEach(player => {
html += `<tr>
<td>${player.id}</td>
@@ -285,7 +285,7 @@ function displayPlayersTable(players) {
</td>
</tr>`;
});
html += '</tbody></table></div>';
document.getElementById('dataContent').innerHTML = html;
}
@@ -293,7 +293,7 @@ function displayPlayersTable(players) {
function displayRunsTable(runs) {
let html = '<div class="table-container"><table class="data-table">';
html += '<thead><tr><th>ID</th><th>Spieler</th><th>Standort</th><th>Zeit</th><th>Datum</th><th>Aktionen</th></tr></thead><tbody>';
runs.forEach(run => {
// Use the time_seconds value from the backend
const timeInSeconds = parseFloat(run.time_seconds) || 0;
@@ -310,7 +310,7 @@ function displayRunsTable(runs) {
</td>
</tr>`;
});
html += '</tbody></table></div>';
document.getElementById('dataContent').innerHTML = html;
}
@@ -318,7 +318,7 @@ function displayRunsTable(runs) {
function displayLocationsTable(locations) {
let html = '<div class="table-container"><table class="data-table">';
html += '<thead><tr><th>ID</th><th>Name</th><th>Latitude</th><th>Longitude</th><th>Erstellt</th><th>Aktionen</th></tr></thead><tbody>';
locations.forEach(location => {
html += `<tr>
<td>${location.id}</td>
@@ -332,7 +332,7 @@ function displayLocationsTable(locations) {
</td>
</tr>`;
});
html += '</tbody></table></div>';
document.getElementById('dataContent').innerHTML = html;
}
@@ -340,7 +340,7 @@ function displayLocationsTable(locations) {
function displayAdminUsersTable(users) {
let html = '<div class="table-container"><table class="data-table">';
html += '<thead><tr><th>ID</th><th>Benutzername</th><th>Access Level</th><th>Aktiv</th><th>Letzter Login</th><th>Aktionen</th></tr></thead><tbody>';
users.forEach(user => {
const isCurrentUser = user.id === currentUser.id;
html += `<tr>
@@ -354,7 +354,7 @@ function displayAdminUsersTable(users) {
</td>
</tr>`;
});
html += '</tbody></table></div>';
document.getElementById('dataContent').innerHTML = html;
}
@@ -375,12 +375,12 @@ function filterData() {
if (!currentData) return;
let filteredData = currentData.filter(item => {
return Object.values(item).some(value =>
return Object.values(item).some(value =>
value && value.toString().toLowerCase().includes(searchTerm)
);
});
switch(currentDataType) {
switch (currentDataType) {
case 'players':
displayPlayersTable(filteredData);
break;
@@ -397,7 +397,7 @@ function filterData() {
}
function refreshData() {
switch(currentDataType) {
switch (currentDataType) {
case 'players':
loadPlayers();
break;
@@ -420,9 +420,9 @@ function showAddModal() {
const modal = document.getElementById('addModal');
const modalTitle = document.getElementById('modalTitle');
const formFields = document.getElementById('formFields');
// Modal-Titel basierend auf aktuellem Datentyp setzen
switch(currentDataType) {
switch (currentDataType) {
case 'players':
modalTitle.textContent = 'Neuen Spieler hinzufügen';
formFields.innerHTML = `
@@ -440,7 +440,7 @@ function showAddModal() {
</div>
`;
break;
case 'locations':
modalTitle.textContent = 'Neuen Standort hinzufügen';
formFields.innerHTML = `
@@ -462,7 +462,7 @@ function showAddModal() {
</div>
`;
break;
case 'adminusers':
modalTitle.textContent = 'Neuen Admin-Benutzer hinzufügen';
formFields.innerHTML = `
@@ -483,7 +483,7 @@ function showAddModal() {
</div>
`;
break;
case 'runs':
modalTitle.textContent = 'Neuen Lauf hinzufügen';
formFields.innerHTML = `
@@ -501,12 +501,12 @@ function showAddModal() {
</div>
`;
break;
default:
modalTitle.textContent = 'Element hinzufügen';
formFields.innerHTML = '<p>Keine Felder für diesen Datentyp verfügbar.</p>';
}
modal.style.display = 'block';
}
@@ -521,21 +521,21 @@ function closeModal() {
async function handleAddSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData.entries());
// Prüfen ob es sich um eine Edit-Operation handelt
const isEdit = data.edit_id;
const editId = data.edit_id;
delete data.edit_id; // edit_id aus den Daten entfernen
try {
let endpoint = '';
let successMessage = '';
let method = 'POST';
switch(currentDataType) {
switch (currentDataType) {
case 'players':
endpoint = isEdit ? `/api/v1/admin/players/${editId}` : '/api/v1/admin/players';
successMessage = isEdit ? 'Spieler erfolgreich aktualisiert' : 'Spieler erfolgreich hinzugefügt';
@@ -560,7 +560,7 @@ async function handleAddSubmit(e) {
showError('Unbekannter Datentyp');
return;
}
const response = await fetch(endpoint, {
method: method,
headers: {
@@ -568,9 +568,9 @@ async function handleAddSubmit(e) {
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showSuccess(successMessage);
closeModal();
@@ -578,7 +578,7 @@ async function handleAddSubmit(e) {
} else {
showError(result.message || `Fehler beim ${isEdit ? 'Aktualisieren' : 'Hinzufügen'}`);
}
} catch (error) {
console.error('Submit failed:', error);
showError(`Fehler beim ${isEdit ? 'Aktualisieren' : 'Hinzufügen'}`);
@@ -589,11 +589,11 @@ async function handleAddSubmit(e) {
async function editPlayer(id) {
const player = currentData.find(p => p.id == id);
if (!player) return;
const modal = document.getElementById('addModal');
const modalTitle = document.getElementById('modalTitle');
const formFields = document.getElementById('formFields');
modalTitle.textContent = 'Spieler bearbeiten';
formFields.innerHTML = `
<div class="form-group">
@@ -610,18 +610,18 @@ async function editPlayer(id) {
</div>
<input type="hidden" name="edit_id" value="${player.id}">
`;
modal.style.display = 'block';
}
async function editLocation(id) {
const location = currentData.find(l => l.id == id);
if (!location) return;
const modal = document.getElementById('addModal');
const modalTitle = document.getElementById('modalTitle');
const formFields = document.getElementById('formFields');
modalTitle.textContent = 'Standort bearbeiten';
formFields.innerHTML = `
<div class="form-group">
@@ -642,7 +642,7 @@ async function editLocation(id) {
</div>
<input type="hidden" name="edit_id" value="${location.id}">
`;
modal.style.display = 'block';
}
@@ -651,24 +651,24 @@ async function editRun(id) {
// Lade die spezifischen Lauf-Daten direkt von der API
const response = await fetch(`/api/admin-runs/${id}`);
const result = await response.json();
if (!result.success) {
showError('Fehler beim Laden der Lauf-Daten: ' + (result.message || 'Unbekannter Fehler'));
return;
}
const run = result.data;
if (!run) {
showError('Lauf nicht gefunden');
return;
}
console.log('Editing run:', run); // Debug log
const modal = document.getElementById('addModal');
const modalTitle = document.getElementById('modalTitle');
const formFields = document.getElementById('formFields');
modalTitle.textContent = 'Lauf bearbeiten';
formFields.innerHTML = `
<div class="form-group">
@@ -685,9 +685,9 @@ async function editRun(id) {
</div>
<input type="hidden" name="edit_id" value="${run.id}">
`;
modal.style.display = 'block';
} catch (error) {
console.error('Error loading run data:', error);
showError('Fehler beim Laden der Lauf-Daten');
@@ -699,7 +699,7 @@ async function deletePlayer(id) {
try {
const response = await fetch(`/api/v1/admin/players/${id}`, { method: 'DELETE' });
const result = await response.json();
if (result.success) {
showSuccess('Spieler erfolgreich gelöscht');
loadPlayers();
@@ -718,7 +718,7 @@ async function deleteRun(id) {
try {
const response = await fetch(`/api/v1/admin/runs/${id}`, { method: 'DELETE' });
const result = await response.json();
if (result.success) {
showSuccess('Lauf erfolgreich gelöscht');
loadRuns();
@@ -737,7 +737,7 @@ async function deleteLocation(id) {
try {
const response = await fetch(`/api/v1/admin/locations/${id}`, { method: 'DELETE' });
const result = await response.json();
if (result.success) {
showSuccess('Standort erfolgreich gelöscht');
loadLocations();
@@ -756,7 +756,7 @@ async function deleteAdminUser(id) {
try {
const response = await fetch(`/api/v1/admin/adminusers/${id}`, { method: 'DELETE' });
const result = await response.json();
if (result.success) {
showSuccess('Admin-Benutzer erfolgreich gelöscht');
loadAdminUsers();
@@ -774,12 +774,12 @@ function confirmDelete(message) {
return new Promise((resolve) => {
document.getElementById('confirmMessage').textContent = message;
document.getElementById('confirmModal').style.display = 'block';
document.getElementById('confirmYes').onclick = () => {
closeModal();
resolve(true);
};
document.getElementById('confirmNo').onclick = () => {
closeModal();
resolve(false);
@@ -806,3 +806,493 @@ function showError(message) {
messageDiv.style.display = 'none';
}, 3000);
}
// ============================================================================
// BLACKLIST MANAGEMENT FUNCTIONS
// ============================================================================
async function showBlacklistManagement() {
currentDataType = 'blacklist';
document.getElementById('blacklistModal').style.display = 'block';
await loadBlacklist();
await loadBlacklistStats();
}
async function loadBlacklist() {
try {
const response = await fetch('/api/v1/admin/blacklist');
const result = await response.json();
if (result.success) {
displayBlacklist(result.data);
} else {
showBlacklistMessage('Fehler beim Laden der Blacklist: ' + result.message, 'error');
}
} catch (error) {
console.error('Error loading blacklist:', error);
showBlacklistMessage('Fehler beim Laden der Blacklist', 'error');
}
}
function displayBlacklist(blacklist) {
const content = document.getElementById('blacklistContent');
let html = '<h3 style="color: #ffffff; margin-bottom: 1rem;">📋 Blacklist-Inhalte</h3>';
Object.entries(blacklist).forEach(([category, terms]) => {
const categoryName = getCategoryDisplayName(category);
const categoryIcon = getCategoryIcon(category);
html += `
<div style="border: 1px solid #334155; padding: 1rem; margin-bottom: 1rem; border-radius: 8px; background: rgba(15, 23, 42, 0.3);">
<h4 style="color: #ffffff; margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.5rem;">
${categoryIcon} ${categoryName}
<span style="background: #1e293b; color: #8892b0; padding: 0.25rem 0.5rem; border-radius: 12px; font-size: 0.8rem;">
${terms.length} Einträge
</span>
</h4>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
`;
if (terms.length === 0) {
html += `
<div style="color: #64748b; font-style: italic; padding: 1rem; text-align: center; width: 100%;">
Keine Einträge in dieser Kategorie
</div>
`;
} else {
terms.forEach(term => {
html += `
<span style="background: #1e293b; color: #e2e8f0; padding: 0.375rem 0.75rem; border-radius: 6px; display: flex; align-items: center; gap: 0.5rem; border: 1px solid #334155;">
<span style="font-family: monospace; font-size: 0.9rem;">${term}</span>
<button onclick="removeFromBlacklist('${term}', '${category}')"
style="background: #dc2626; color: white; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 12px; display: flex; align-items: center; justify-content: center; transition: background-color 0.2s;"
onmouseover="this.style.backgroundColor='#b91c1c'"
onmouseout="this.style.backgroundColor='#dc2626'"
title="Entfernen">
×
</button>
</span>
`;
});
}
html += `
</div>
</div>
`;
});
content.innerHTML = html;
}
// Kategorie-Icons hinzufügen
function getCategoryIcon(category) {
const icons = {
historical: '🏛️',
offensive: '⚠️',
titles: '👑',
brands: '🏷️',
inappropriate: '🚫'
};
return icons[category] || '📝';
}
function getCategoryDisplayName(category) {
const names = {
historical: 'Historisch belastet',
offensive: 'Beleidigend/anstößig',
titles: 'Titel/Berufsbezeichnung',
brands: 'Markenname',
inappropriate: 'Unpassend'
};
return names[category] || category;
}
async function testNameAgainstBlacklist() {
const firstname = document.getElementById('testFirstname').value.trim();
const lastname = document.getElementById('testLastname').value.trim();
const resultDiv = document.getElementById('testResult');
if (!firstname || !lastname) {
showBlacklistMessage('Bitte gib Vorname und Nachname ein', 'error');
return;
}
try {
const response = await fetch('/api/v1/admin/blacklist/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ firstname, lastname })
});
const result = await response.json();
if (result.success) {
const testResult = result.data;
if (testResult.isBlocked) {
let matchTypeText = '';
let similarityText = '';
if (testResult.matchType === 'exact') {
matchTypeText = 'Exakte Übereinstimmung';
} else if (testResult.matchType === 'similar') {
matchTypeText = 'Ähnliche Übereinstimmung (Levenshtein)';
const similarityPercent = Math.round((1 - testResult.similarity) * 100);
similarityText = `<br>Ähnlichkeit: ${similarityPercent}% (Distanz: ${testResult.levenshteinDistance})`;
}
resultDiv.innerHTML = `
<div style="background: #ffebee; color: #c62828; padding: 0.5rem; border-radius: 3px;">
<strong>❌ Name ist blockiert</strong><br>
Grund: ${testResult.reason}<br>
Kategorie: ${getCategoryDisplayName(testResult.category)}<br>
Gefundener Begriff: "${testResult.matchedTerm}"<br>
Typ: ${matchTypeText}${similarityText}
</div>
`;
} else {
resultDiv.innerHTML = `
<div style="background: #e8f5e8; color: #2e7d32; padding: 0.5rem; border-radius: 3px;">
<strong>✅ Name ist erlaubt</strong><br>
Der Name "${firstname} ${lastname}" ist nicht in der Blacklist.
</div>
`;
}
resultDiv.style.display = 'block';
} else {
showBlacklistMessage('Fehler beim Testen: ' + result.message, 'error');
}
} catch (error) {
console.error('Error testing name:', error);
showBlacklistMessage('Fehler beim Testen des Namens', 'error');
}
}
async function addToBlacklist() {
const term = document.getElementById('newTerm').value.trim();
const category = document.getElementById('newCategory').value;
if (!term) {
showBlacklistMessage('Bitte gib einen Begriff ein', 'error');
return;
}
try {
const response = await fetch('/api/v1/admin/blacklist', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ term, category })
});
const result = await response.json();
if (result.success) {
showBlacklistMessage('Begriff erfolgreich hinzugefügt', 'success');
document.getElementById('newTerm').value = '';
await loadBlacklist();
await loadBlacklistStats();
} else {
showBlacklistMessage('Fehler beim Hinzufügen: ' + result.message, 'error');
}
} catch (error) {
console.error('Error adding to blacklist:', error);
showBlacklistMessage('Fehler beim Hinzufügen zur Blacklist', 'error');
}
}
async function removeFromBlacklist(term, category) {
if (!confirm(`Möchtest du "${term}" aus der Kategorie "${getCategoryDisplayName(category)}" entfernen?`)) {
return;
}
try {
const response = await fetch('/api/v1/admin/blacklist', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ term, category })
});
const result = await response.json();
if (result.success) {
showBlacklistMessage('Begriff erfolgreich entfernt', 'success');
await loadBlacklist();
await loadBlacklistStats();
} else {
showBlacklistMessage('Fehler beim Entfernen: ' + result.message, 'error');
}
} catch (error) {
console.error('Error removing from blacklist:', error);
showBlacklistMessage('Fehler beim Entfernen aus der Blacklist', 'error');
}
}
function showBlacklistMessage(message, type) {
const messageDiv = document.getElementById('blacklistMessage');
messageDiv.textContent = message;
messageDiv.className = `message ${type}`;
messageDiv.style.display = 'block';
setTimeout(() => {
messageDiv.style.display = 'none';
}, 3000);
}
// Blacklist-Statistiken laden
async function loadBlacklistStats() {
try {
const response = await fetch('/api/v1/admin/blacklist/stats');
const result = await response.json();
if (result.success) {
displayBlacklistStats(result.data);
} else {
console.error('Error loading blacklist stats:', result.message);
}
} catch (error) {
console.error('Error loading blacklist stats:', error);
}
}
// Blacklist-Statistiken anzeigen
function displayBlacklistStats(stats) {
// Erstelle oder aktualisiere Statistiken-Bereich
let statsDiv = document.getElementById('blacklistStats');
if (!statsDiv) {
// Erstelle Statistiken-Bereich am Anfang des Modals
const modalContent = document.querySelector('#blacklistModal .modal-content');
const firstChild = modalContent.firstChild;
statsDiv = document.createElement('div');
statsDiv.id = 'blacklistStats';
statsDiv.style.cssText = 'border: 1px solid #4ade80; padding: 1rem; margin-bottom: 1rem; border-radius: 5px; background: rgba(34, 197, 94, 0.1);';
modalContent.insertBefore(statsDiv, firstChild);
}
let html = `
<h4 style="color: #4ade80; margin-bottom: 1rem;">📊 Blacklist-Statistiken</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; margin-bottom: 1rem;">
`;
stats.categories.forEach(category => {
const categoryName = getCategoryDisplayName(category.category);
const lastAdded = new Date(category.last_added).toLocaleDateString('de-DE');
html += `
<div style="background: rgba(15, 23, 42, 0.5); padding: 0.75rem; border-radius: 5px; text-align: center;">
<div style="font-size: 1.5rem; font-weight: bold; color: #4ade80;">${category.count}</div>
<div style="font-size: 0.9rem; color: #8892b0;">${categoryName}</div>
<div style="font-size: 0.8rem; color: #64748b;">Letzte: ${lastAdded}</div>
</div>
`;
});
html += `
</div>
<div style="text-align: center; padding: 0.5rem; background: rgba(15, 23, 42, 0.3); border-radius: 5px;">
<strong style="color: #4ade80;">Gesamt: ${stats.total} Begriffe</strong>
</div>
`;
statsDiv.innerHTML = html;
}
// LLM-Management
function showLLMManagement() {
document.getElementById('llmModal').style.display = 'block';
loadLLMStatus();
}
function closeLLMModal() {
document.getElementById('llmModal').style.display = 'none';
}
// LLM-Status laden
async function loadLLMStatus() {
try {
const response = await fetch('/api/v1/admin/llm/status', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('adminToken')}`
}
});
const result = await response.json();
const statusContent = document.getElementById('llmStatusContent');
if (result.success) {
const status = result.data;
if (status.connected) {
statusContent.innerHTML = `
<div style="background: #e8f5e8; color: #2e7d32; padding: 0.5rem; border-radius: 3px;">
<strong>✅ KI-Moderator verbunden</strong><br>
Modell: ${status.model}<br>
URL: ${status.baseUrl}
</div>
`;
} else {
statusContent.innerHTML = `
<div style="background: #ffebee; color: #c62828; padding: 0.5rem; border-radius: 3px;">
<strong>❌ KI-Moderator nicht verfügbar</strong><br>
Modell: ${status.model}<br>
URL: ${status.baseUrl}<br>
Fehler: ${status.error}
</div>
`;
}
} else {
statusContent.innerHTML = `
<div style="background: #ffebee; color: #c62828; padding: 0.5rem; border-radius: 3px;">
<strong>❌ Fehler beim Laden des Status</strong><br>
${result.message}
</div>
`;
}
} catch (error) {
console.error('Error loading LLM status:', error);
document.getElementById('llmStatusContent').innerHTML = `
<div style="background: #ffebee; color: #c62828; padding: 0.5rem; border-radius: 3px;">
<strong>❌ Fehler beim Laden des Status</strong><br>
${error.message}
</div>
`;
}
}
// Name mit LLM testen
async function testNameWithLLM() {
const firstname = document.getElementById('llmFirstname').value.trim();
const lastname = document.getElementById('llmLastname').value.trim();
const context = document.getElementById('llmContext').value.trim();
if (!firstname || !lastname) {
showLLMMessage('Bitte gib Vorname und Nachname ein', 'error');
return;
}
try {
// LLM-Test
const llmResponse = await fetch('/api/v1/admin/llm/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('adminToken')}`
},
body: JSON.stringify({ firstname, lastname, context })
});
const llmResult = await llmResponse.json();
// Blacklist-Test zum Vergleich
const blacklistResponse = await fetch('/api/v1/admin/blacklist/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('adminToken')}`
},
body: JSON.stringify({ firstname, lastname })
});
const blacklistResult = await blacklistResponse.json();
// Ergebnisse anzeigen
displayLLMResults(llmResult, blacklistResult);
} catch (error) {
console.error('Error testing name with LLM:', error);
showLLMMessage('Fehler beim Testen: ' + error.message, 'error');
}
}
// LLM-Ergebnisse anzeigen
function displayLLMResults(llmResult, blacklistResult) {
const resultDiv = document.getElementById('llmResult');
const resultContent = document.getElementById('llmResultContent');
const comparisonDiv = document.getElementById('llmComparison');
const comparisonContent = document.getElementById('llmComparisonContent');
if (llmResult.success) {
const llm = llmResult.data;
let llmStatus = '';
if (llm.isBlocked) {
llmStatus = `
<div style="background: #ffebee; color: #c62828; padding: 0.5rem; border-radius: 3px;">
<strong>❌ Name blockiert</strong><br>
Grund: ${llm.reason}<br>
Konfidenz: ${Math.round(llm.confidence * 100)}%<br>
LLM-Antwort: "${llm.llmResponse}"<br>
Typ: ${llm.matchType}
</div>
`;
} else {
llmStatus = `
<div style="background: #e8f5e8; color: #2e7d32; padding: 0.5rem; border-radius: 3px;">
<strong>✅ Name erlaubt</strong><br>
Grund: ${llm.reason}<br>
Konfidenz: ${Math.round(llm.confidence * 100)}%<br>
LLM-Antwort: "${llm.llmResponse}"<br>
Typ: ${llm.matchType}
</div>
`;
}
resultContent.innerHTML = llmStatus;
resultDiv.style.display = 'block';
// Vergleich mit Blacklist
if (blacklistResult.success) {
const blacklist = blacklistResult.data;
let comparisonStatus = '';
if (blacklist.combined.isBlocked) {
comparisonStatus = `
<div style="background: #fff3e0; color: #f57c00; padding: 0.5rem; border-radius: 3px;">
<strong>⚠️ Name blockiert (${blacklist.combined.source})</strong><br>
Grund: ${blacklist.combined.reason}
</div>
`;
} else {
comparisonStatus = `
<div style="background: #e8f5e8; color: #2e7d32; padding: 0.5rem; border-radius: 3px;">
<strong>✅ Name erlaubt</strong><br>
Sowohl KI als auch Blacklist erlauben den Namen
</div>
`;
}
comparisonContent.innerHTML = comparisonStatus;
comparisonDiv.style.display = 'block';
}
} else {
resultContent.innerHTML = `
<div style="background: #ffebee; color: #c62828; padding: 0.5rem; border-radius: 3px;">
<strong>❌ Fehler beim Testen</strong><br>
${llmResult.message}
</div>
`;
resultDiv.style.display = 'block';
}
}
// LLM-Nachricht anzeigen
function showLLMMessage(message, type) {
const resultDiv = document.getElementById('llmResult');
const resultContent = document.getElementById('llmResultContent');
const color = type === 'error' ? '#c62828' : '#2e7d32';
const bgColor = type === 'error' ? '#ffebee' : '#e8f5e8';
resultContent.innerHTML = `
<div style="background: ${bgColor}; color: ${color}; padding: 0.5rem; border-radius: 3px;">
<strong>${type === 'error' ? '❌' : '✅'} ${message}</strong>
</div>
`;
resultDiv.style.display = 'block';
}