1
0
Fork 0
forked from Simnation/Main
Main/resources/[tools]/nordi_license/html/script.js

448 lines
15 KiB
JavaScript
Raw Normal View History

2025-08-04 06:14:47 +02:00
let currentLicense = null;
2025-08-04 06:53:42 +02:00
let isCardFlipped = false;
let cameraStream = null;
2025-08-04 06:14:47 +02:00
// Event Listener für Nachrichten von FiveM
window.addEventListener('message', function(event) {
const data = event.data;
switch(data.action) {
case 'showLicense':
showLicense(data.data);
break;
2025-08-04 06:53:42 +02:00
case 'hideLicense':
closeLicense();
break;
case 'openCamera':
openCamera();
break;
2025-08-04 06:14:47 +02:00
}
});
// Lizenz anzeigen
function showLicense(data) {
currentLicense = data;
const container = document.getElementById('license-container');
const card = document.getElementById('license-card');
2025-08-04 06:53:42 +02:00
// Loading anzeigen
showLoading();
2025-08-04 06:14:47 +02:00
2025-08-04 06:53:42 +02:00
setTimeout(() => {
// Lizenztyp-spezifische Klasse hinzufügen
card.className = 'license-card ' + data.license.license_type;
// Header befüllen
document.getElementById('license-title').textContent = data.config.label;
document.getElementById('license-icon').className = 'license-icon ' + data.config.icon;
// Persönliche Daten
document.getElementById('license-name').textContent = data.license.name || 'N/A';
document.getElementById('license-birthday').textContent = formatDate(data.license.birthday) || 'N/A';
document.getElementById('license-gender').textContent = formatGender(data.license.gender) || 'N/A';
// Dokument-Informationen
document.getElementById('license-issue').textContent = formatDate(data.license.issue_date) || 'N/A';
document.getElementById('license-expire').textContent = formatDate(data.license.expire_date) || 'N/A';
document.getElementById('license-id').textContent = '#' + (data.license.id || '000000').toString().padStart(6, '0');
document.getElementById('license-issuer').textContent = data.license.issued_by_name || 'Behörde';
// Foto anzeigen
displayPlayerPhoto(data.license);
// Klassen anzeigen (nur bei Führerschein)
displayLicenseClasses(data.license);
// Status und Gültigkeit
displayLicenseStatus(data.license);
displayValidityIndicator(data.license);
// Rückseite vorbereiten
prepareBackSide(data.license);
// Container anzeigen
hideLoading();
container.classList.remove('hidden');
// Sound-Effekt
playSound('card-flip-sound');
// Notification
showNotification('Lizenz geladen', 'success');
}, 500);
}
// Spieler-Foto anzeigen
function displayPlayerPhoto(license) {
const photoImg = document.getElementById('player-photo');
const photoPlaceholder = document.getElementById('photo-placeholder');
2025-08-04 06:14:47 +02:00
2025-08-04 06:53:42 +02:00
if (license.photo_url && license.photo_url !== '') {
photoImg.src = license.photo_url;
photoImg.onload = function() {
photoImg.classList.remove('hidden');
photoPlaceholder.classList.add('hidden');
};
photoImg.onerror = function() {
photoImg.classList.add('hidden');
photoPlaceholder.classList.remove('hidden');
};
} else {
photoImg.classList.add('hidden');
photoPlaceholder.classList.remove('hidden');
}
}
// Lizenz-Klassen anzeigen
function displayLicenseClasses(license) {
2025-08-04 06:14:47 +02:00
const classesRow = document.getElementById('license-classes-row');
2025-08-04 06:53:42 +02:00
const classesElement = document.getElementById('license-classes');
if (license.license_type === 'drivers_license' && license.classes && license.classes !== '[]') {
2025-08-04 06:14:47 +02:00
try {
2025-08-04 06:53:42 +02:00
const classes = JSON.parse(license.classes);
2025-08-04 06:14:47 +02:00
if (classes && classes.length > 0) {
2025-08-04 06:53:42 +02:00
classesElement.textContent = classes.join(', ');
2025-08-04 06:14:47 +02:00
classesRow.style.display = 'flex';
2025-08-04 06:53:42 +02:00
return;
2025-08-04 06:14:47 +02:00
}
} catch (e) {
2025-08-04 06:53:42 +02:00
console.error('Fehler beim Parsen der Klassen:', e);
2025-08-04 06:14:47 +02:00
}
}
2025-08-04 06:53:42 +02:00
classesRow.style.display = 'none';
}
// Lizenz-Status anzeigen
function displayLicenseStatus(license) {
2025-08-04 06:14:47 +02:00
const statusElement = document.getElementById('license-status');
2025-08-04 06:53:42 +02:00
const statusIcon = statusElement.querySelector('.status-icon');
const statusText = statusElement.querySelector('.status-text');
// Ablaufdatum prüfen
let isExpired = false;
let isExpiringSoon = false;
if (license.expire_date) {
const expireDate = new Date(license.expire_date);
const today = new Date();
const daysUntilExpire = Math.ceil((expireDate - today) / (1000 * 60 * 60 * 24));
isExpired = daysUntilExpire < 0;
isExpiringSoon = daysUntilExpire <= 30 && daysUntilExpire >= 0;
}
// Status setzen
if (!license.is_active || isExpired) {
statusElement.className = 'license-status inactive';
statusIcon.className = 'status-icon fas fa-times-circle';
statusText.textContent = isExpired ? 'Abgelaufen' : 'Ungültig';
} else if (isExpiringSoon) {
statusElement.className = 'license-status warning';
statusIcon.className = 'status-icon fas fa-exclamation-triangle';
statusText.textContent = 'Läuft bald ab';
} else {
2025-08-04 06:14:47 +02:00
statusElement.className = 'license-status active';
2025-08-04 06:53:42 +02:00
statusIcon.className = 'status-icon fas fa-check-circle';
statusText.textContent = 'Gültig';
}
}
// Gültigkeits-Indikator anzeigen
function displayValidityIndicator(license) {
const validityFill = document.getElementById('validity-fill');
const validityText = document.getElementById('validity-text');
if (!license.expire_date) {
validityText.textContent = 'Unbegrenzt gültig';
validityFill.style.width = '100%';
validityFill.style.backgroundColor = '#4CAF50';
return;
}
const issueDate = new Date(license.issue_date);
const expireDate = new Date(license.expire_date);
const today = new Date();
const totalDays = Math.ceil((expireDate - issueDate) / (1000 * 60 * 60 * 24));
const remainingDays = Math.ceil((expireDate - today) / (1000 * 60 * 60 * 24));
const percentage = Math.max(0, Math.min(100, (remainingDays / totalDays) * 100));
validityFill.style.width = percentage + '%';
if (remainingDays < 0) {
validityText.textContent = 'Abgelaufen';
validityFill.style.backgroundColor = '#f44336';
} else if (remainingDays <= 30) {
validityText.textContent = `Noch ${remainingDays} Tage gültig`;
validityFill.style.backgroundColor = '#ff9800';
2025-08-04 06:14:47 +02:00
} else {
2025-08-04 06:53:42 +02:00
validityText.textContent = `Noch ${remainingDays} Tage gültig`;
validityFill.style.backgroundColor = '#4CAF50';
}
}
// Rückseite vorbereiten
function prepareBackSide(license) {
const classesGrid = document.getElementById('classes-grid');
const restrictionsList = document.getElementById('restrictions-list');
const notesText = document.getElementById('notes-text');
// Klassen-Grid für Führerschein
if (license.license_type === 'drivers_license' && license.classes) {
try {
const classes = JSON.parse(license.classes);
classesGrid.innerHTML = '';
const classDescriptions = {
'A': 'Motorräder',
'A1': 'Leichte Motorräder',
'A2': 'Mittlere Motorräder',
'B': 'PKW',
'BE': 'PKW mit Anhänger',
'C': 'LKW',
'CE': 'LKW mit Anhänger',
'D': 'Bus',
'DE': 'Bus mit Anhänger'
};
classes.forEach(cls => {
const classItem = document.createElement('div');
classItem.className = 'class-item';
classItem.innerHTML = `
<div class="class-letter">${cls}</div>
<div class="class-description">${classDescriptions[cls] || 'Unbekannt'}</div>
`;
classesGrid.appendChild(classItem);
});
} catch (e) {
classesGrid.innerHTML = '<p>Keine Klassen verfügbar</p>';
}
} else {
classesGrid.innerHTML = '<p>Nicht zutreffend</p>';
2025-08-04 06:14:47 +02:00
}
2025-08-04 06:53:42 +02:00
// Beschränkungen (Beispiel)
restrictionsList.innerHTML = '<li>Keine besonderen Beschränkungen</li>';
// Bemerkungen
notesText.textContent = license.notes || 'Keine besonderen Bemerkungen';
2025-08-04 06:14:47 +02:00
}
2025-08-04 06:53:42 +02:00
// Karte drehen
function flipCard() {
const frontSide = document.querySelector('.license-content, .license-footer');
const backSide = document.getElementById('license-back');
isCardFlipped = !isCardFlipped;
2025-08-04 06:51:25 +02:00
2025-08-04 06:53:42 +02:00
if (isCardFlipped) {
// Zur Rückseite
document.querySelector('.license-content').classList.add('hidden');
document.querySelector('.license-footer').classList.add('hidden');
backSide.classList.remove('hidden');
2025-08-04 06:51:25 +02:00
} else {
2025-08-04 06:53:42 +02:00
// Zur Vorderseite
document.querySelector('.license-content').classList.remove('hidden');
document.querySelector('.license-footer').classList.remove('hidden');
backSide.classList.add('hidden');
2025-08-04 06:51:25 +02:00
}
2025-08-04 06:53:42 +02:00
playSound('card-flip-sound');
}
2025-08-04 06:51:25 +02:00
2025-08-04 06:53:42 +02:00
// Kamera öffnen
async function openCamera() {
const container = document.getElementById('camera-container');
const video = document.getElementById('camera-video');
try {
cameraStream = await navigator.mediaDevices.getUserMedia({
video: {
width: 640,
height: 480,
facingMode: 'user'
}
});
video.srcObject = cameraStream;
container.classList.remove('hidden');
showNotification('Kamera geöffnet', 'info');
} catch (err) {
console.error('Kamera-Zugriff fehlgeschlagen:', err);
showNotification('Kamera-Zugriff fehlgeschlagen', 'error');
}
}
// Foto aufnehmen
function takePhoto() {
const video = document.getElementById('camera-video');
const canvas = document.getElementById('camera-canvas');
const ctx = canvas.getContext('2d');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0);
const photoData = canvas.toDataURL('image/jpeg', 0.8);
// Sound-Effekt
playSound('camera-shutter-sound');
// An FiveM senden
fetch(`https://${GetParentResourceName()}/savePhoto`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
photo: photoData,
citizenid: currentLicense?.license?.citizenid
})
}).then(() => {
showNotification('Foto gespeichert', 'success');
closeCamera();
}).catch(err => {
console.error('Fehler beim Speichern:', err);
showNotification('Fehler beim Speichern', 'error');
});
}
// Kamera schließen
function closeCamera() {
const container = document.getElementById('camera-container');
if (cameraStream) {
cameraStream.getTracks().forEach(track => track.stop());
cameraStream = null;
}
container.classList.add('hidden');
2025-08-04 06:14:47 +02:00
}
// Lizenz schließen
function closeLicense() {
const container = document.getElementById('license-container');
container.classList.add('hidden');
2025-08-04 06:53:42 +02:00
// Karte zurücksetzen
isCardFlipped = false;
document.querySelector('.license-content').classList.remove('hidden');
document.querySelector('.license-footer').classList.remove('hidden');
document.getElementById('license-back').classList.add('hidden');
// Callback an FiveM
2025-08-04 06:14:47 +02:00
fetch(`https://${GetParentResourceName()}/closeLicense`, {
method: 'POST',
headers: {
2025-08-04 06:53:42 +02:00
'Content-Type': 'application/json',
2025-08-04 06:14:47 +02:00
},
body: JSON.stringify({})
2025-08-04 06:53:42 +02:00
}).catch(() => {}); // Fehler ignorieren
}
// Hilfsfunktionen
function formatGender(gender) {
const genderMap = {
'male': 'Männlich',
'female': 'Weiblich',
'other': 'Divers',
'm': 'Männlich',
'f': 'Weiblich'
};
return genderMap[gender?.toLowerCase()] || gender || 'Unbekannt';
2025-08-04 06:14:47 +02:00
}
2025-08-04 06:53:42 +02:00
function formatDate(dateString) {
if (!dateString) return null;
try {
const date = new Date(dateString);
return date.toLocaleDateString('de-DE');
} catch (e) {
return dateString;
}
}
function showLoading() {
document.getElementById('loading-overlay').classList.remove('hidden');
}
function hideLoading() {
document.getElementById('loading-overlay').classList.add('hidden');
}
function playSound(soundId) {
const audio = document.getElementById(soundId);
if (audio) {
audio.volume = 0.3;
audio.play().catch(() => {}); // Fehler ignorieren
}
}
function showNotification(message, type = 'info') {
const container = document.getElementById('notification-container');
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="notification-icon fas ${getNotificationIcon(type)}"></i>
<span class="notification-text">${message}</span>
</div>
<button class="notification-close" onclick="this.parentElement.remove()">
<i class="fas fa-times"></i>
</button>
`;
container.appendChild(notification);
// Auto-remove nach 5 Sekunden
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 5000);
}
function getNotificationIcon(type) {
const icons = {
'success': 'fa-check-circle',
'error': 'fa-exclamation-circle',
'warning': 'fa-exclamation-triangle',
'info': 'fa-info-circle'
};
return icons[type] || icons.info;
}
// Event Listeners
2025-08-04 06:14:47 +02:00
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
2025-08-04 06:53:42 +02:00
if (!document.getElementById('camera-container').classList.contains('hidden')) {
closeCamera();
} else if (!document.getElementById('license-container').classList.contains('hidden')) {
closeLicense();
}
}
if (event.key === 'f' || event.key === 'F') {
if (!document.getElementById('license-container').classList.contains('hidden')) {
flipCard();
}
2025-08-04 06:14:47 +02:00
}
});
2025-08-04 06:53:42 +02:00
// Klick außerhalb zum Schließen
2025-08-04 06:14:47 +02:00
document.getElementById('license-container').addEventListener('click', function(event) {
2025-08-04 06:53:42 +02:00
if (event.target.classList.contains('license-overlay')) {
2025-08-04 06:14:47 +02:00
closeLicense();
}
});
2025-08-04 06:53:42 +02:00
// Initialisierung
document.addEventListener('DOMContentLoaded', function() {
console.log('License System UI geladen');
});