forked from Simnation/Main
ed
This commit is contained in:
parent
05be118a84
commit
2f2d0b1103
3 changed files with 60 additions and 142 deletions
|
@ -425,10 +425,17 @@ openRevokeLicenseMenu = function(targetId, targetName, licenses)
|
||||||
lib.showContext('revoke_license')
|
lib.showContext('revoke_license')
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Manual License Entry Menu
|
-- Manual License Entry Menu (Vollständig manuell)
|
||||||
openManualLicenseEntry = function(targetId, targetName)
|
openManualLicenseEntry = function(targetId, targetName)
|
||||||
debugPrint("Öffne manuelle Lizenz-Eingabe für: " .. targetName)
|
debugPrint("Öffne manuelle Lizenz-Eingabe für: " .. targetName)
|
||||||
|
|
||||||
|
-- Aktuelles Datum für Standardwerte
|
||||||
|
local currentDate = os.date("%d.%m.%Y")
|
||||||
|
|
||||||
|
-- Berechne Standardablaufdatum (1 Jahr später)
|
||||||
|
local day, month, year = currentDate:match("(%d+)%.(%d+)%.(%d+)")
|
||||||
|
local defaultExpireDate = day .. "." .. month .. "." .. (tonumber(year) + 1)
|
||||||
|
|
||||||
local input = lib.inputDialog('Lizenz manuell ausstellen', {
|
local input = lib.inputDialog('Lizenz manuell ausstellen', {
|
||||||
{type = 'select', label = 'Lizenztyp', options = getLicenseTypeOptions()},
|
{type = 'select', label = 'Lizenztyp', options = getLicenseTypeOptions()},
|
||||||
{type = 'input', label = 'Name', default = targetName},
|
{type = 'input', label = 'Name', default = targetName},
|
||||||
|
@ -438,30 +445,44 @@ openManualLicenseEntry = function(targetId, targetName)
|
||||||
{value = 'female', label = 'Weiblich'},
|
{value = 'female', label = 'Weiblich'},
|
||||||
{value = 'other', label = 'Divers'}
|
{value = 'other', label = 'Divers'}
|
||||||
}},
|
}},
|
||||||
{type = 'date', label = 'Ausstellungsdatum', default = os.date("%Y-%m-%d")},
|
{type = 'input', label = 'Ausstellungsdatum', description = 'Format: DD.MM.YYYY', default = currentDate},
|
||||||
{type = 'date', label = 'Ablaufdatum', default = os.date("%Y-%m-%d", os.time() + 365*24*60*60)},
|
{type = 'input', label = 'Ablaufdatum', description = 'Format: DD.MM.YYYY', default = defaultExpireDate},
|
||||||
|
{type = 'input', label = 'Klassen (kommagetrennt)', description = 'z.B. A,B,C', default = ''},
|
||||||
|
{type = 'input', label = 'Bemerkungen', default = ''},
|
||||||
{type = 'checkbox', label = 'Foto aufnehmen?'}
|
{type = 'checkbox', label = 'Foto aufnehmen?'}
|
||||||
})
|
})
|
||||||
|
|
||||||
if not input then return end
|
if not input then return end
|
||||||
|
|
||||||
local licenseType = input[1]
|
local licenseType = input[1]
|
||||||
|
|
||||||
|
-- Klassen verarbeiten
|
||||||
|
local classes = {}
|
||||||
|
if input[7] and input[7] ~= "" then
|
||||||
|
for class in string.gmatch(input[7], '([^,]+)') do
|
||||||
|
table.insert(classes, class:match("^%s*(.-)%s*$")) -- Leerzeichen entfernen
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local licenseData = {
|
local licenseData = {
|
||||||
name = input[2],
|
name = input[2],
|
||||||
birthday = input[3],
|
birthday = input[3],
|
||||||
gender = input[4],
|
gender = input[4],
|
||||||
issue_date = os.date("%d.%m.%Y", os.time(os.date("!*t", input[5] / 1000))),
|
issue_date = input[5],
|
||||||
expire_date = os.date("%d.%m.%Y", os.time(os.date("!*t", input[6] / 1000))),
|
expire_date = input[6],
|
||||||
|
classes = classes,
|
||||||
|
notes = input[8],
|
||||||
license_type = licenseType
|
license_type = licenseType
|
||||||
}
|
}
|
||||||
|
|
||||||
if input[7] then -- Take photo
|
if input[9] then -- Foto aufnehmen
|
||||||
TriggerEvent('license-system:client:openCamera', targetId, licenseData)
|
TriggerEvent('license-system:client:openCamera', targetId, licenseData)
|
||||||
else
|
else
|
||||||
TriggerServerEvent('license-system:server:issueManualLicense', targetId, licenseData)
|
TriggerServerEvent('license-system:server:issueManualLicense', targetId, licenseData)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- License Reactivation Menu
|
-- License Reactivation Menu
|
||||||
openReactivateLicenseMenu = function(targetId, targetName)
|
openReactivateLicenseMenu = function(targetId, targetName)
|
||||||
debugPrint("Öffne Lizenz-Reaktivierungs-Menü für: " .. targetName)
|
debugPrint("Öffne Lizenz-Reaktivierungs-Menü für: " .. targetName)
|
||||||
|
|
|
@ -19,7 +19,7 @@ window.addEventListener('message', function(event) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Lizenz anzeigen
|
// In der showLicense Funktion in script.js
|
||||||
function showLicense(data) {
|
function showLicense(data) {
|
||||||
currentLicense = data;
|
currentLicense = data;
|
||||||
const container = document.getElementById('license-container');
|
const container = document.getElementById('license-container');
|
||||||
|
@ -69,121 +69,10 @@ function showLicense(data) {
|
||||||
|
|
||||||
// Notification
|
// Notification
|
||||||
showNotification('Lizenz geladen', 'success');
|
showNotification('Lizenz geladen', 'success');
|
||||||
|
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spieler-Foto anzeigen
|
// Erweitere die prepareBackSide Funktion um Bemerkungen anzuzeigen
|
||||||
function displayPlayerPhoto(license) {
|
|
||||||
const photoImg = document.getElementById('player-photo');
|
|
||||||
const photoPlaceholder = document.getElementById('photo-placeholder');
|
|
||||||
|
|
||||||
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) {
|
|
||||||
const classesRow = document.getElementById('license-classes-row');
|
|
||||||
const classesElement = document.getElementById('license-classes');
|
|
||||||
|
|
||||||
if (license.license_type === 'drivers_license' && license.classes && license.classes !== '[]') {
|
|
||||||
try {
|
|
||||||
const classes = JSON.parse(license.classes);
|
|
||||||
if (classes && classes.length > 0) {
|
|
||||||
classesElement.textContent = classes.join(', ');
|
|
||||||
classesRow.style.display = 'flex';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Fehler beim Parsen der Klassen:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
classesRow.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lizenz-Status anzeigen
|
|
||||||
function displayLicenseStatus(license) {
|
|
||||||
const statusElement = document.getElementById('license-status');
|
|
||||||
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 {
|
|
||||||
statusElement.className = 'license-status active';
|
|
||||||
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';
|
|
||||||
} else {
|
|
||||||
validityText.textContent = `Noch ${remainingDays} Tage gültig`;
|
|
||||||
validityFill.style.backgroundColor = '#4CAF50';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rückseite vorbereiten
|
|
||||||
function prepareBackSide(license) {
|
function prepareBackSide(license) {
|
||||||
const classesGrid = document.getElementById('classes-grid');
|
const classesGrid = document.getElementById('classes-grid');
|
||||||
const restrictionsList = document.getElementById('restrictions-list');
|
const restrictionsList = document.getElementById('restrictions-list');
|
||||||
|
@ -192,7 +81,7 @@ function prepareBackSide(license) {
|
||||||
// Klassen-Grid für Führerschein
|
// Klassen-Grid für Führerschein
|
||||||
if (license.license_type === 'drivers_license' && license.classes) {
|
if (license.license_type === 'drivers_license' && license.classes) {
|
||||||
try {
|
try {
|
||||||
const classes = JSON.parse(license.classes);
|
const classes = Array.isArray(license.classes) ? license.classes : JSON.parse(license.classes);
|
||||||
classesGrid.innerHTML = '';
|
classesGrid.innerHTML = '';
|
||||||
|
|
||||||
const classDescriptions = {
|
const classDescriptions = {
|
||||||
|
@ -207,15 +96,19 @@ function prepareBackSide(license) {
|
||||||
'DE': 'Bus mit Anhänger'
|
'DE': 'Bus mit Anhänger'
|
||||||
};
|
};
|
||||||
|
|
||||||
classes.forEach(cls => {
|
if (classes && classes.length > 0) {
|
||||||
const classItem = document.createElement('div');
|
classes.forEach(cls => {
|
||||||
classItem.className = 'class-item';
|
const classItem = document.createElement('div');
|
||||||
classItem.innerHTML = `
|
classItem.className = 'class-item';
|
||||||
<div class="class-letter">${cls}</div>
|
classItem.innerHTML = `
|
||||||
<div class="class-description">${classDescriptions[cls] || 'Unbekannt'}</div>
|
<div class="class-letter">${cls}</div>
|
||||||
`;
|
<div class="class-description">${classDescriptions[cls] || 'Unbekannt'}</div>
|
||||||
classesGrid.appendChild(classItem);
|
`;
|
||||||
});
|
classesGrid.appendChild(classItem);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
classesGrid.innerHTML = '<p>Keine Klassen verfügbar</p>';
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
classesGrid.innerHTML = '<p>Keine Klassen verfügbar</p>';
|
classesGrid.innerHTML = '<p>Keine Klassen verfügbar</p>';
|
||||||
}
|
}
|
||||||
|
@ -230,6 +123,7 @@ function prepareBackSide(license) {
|
||||||
notesText.textContent = license.notes || 'Keine besonderen Bemerkungen';
|
notesText.textContent = license.notes || 'Keine besonderen Bemerkungen';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Karte drehen
|
// Karte drehen
|
||||||
function flipCard() {
|
function flipCard() {
|
||||||
const frontSide = document.querySelector('.license-content, .license-footer');
|
const frontSide = document.querySelector('.license-content, .license-footer');
|
||||||
|
|
|
@ -805,7 +805,7 @@ RegisterNetEvent('license-system:server:reactivateLicense', function(targetId, l
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- EVENT HANDLER: Manuelle Lizenz ausstellen
|
-- EVENT HANDLER: Manuelle Lizenz ausstellen (Erweitert)
|
||||||
RegisterNetEvent('license-system:server:issueManualLicense', function(targetId, licenseData)
|
RegisterNetEvent('license-system:server:issueManualLicense', function(targetId, licenseData)
|
||||||
local src = source
|
local src = source
|
||||||
debugPrint("=== Event: issueManualLicense ===")
|
debugPrint("=== Event: issueManualLicense ===")
|
||||||
|
@ -833,29 +833,29 @@ RegisterNetEvent('license-system:server:issueManualLicense', function(targetId,
|
||||||
local targetCitizenId = targetPlayer.PlayerData.citizenid
|
local targetCitizenId = targetPlayer.PlayerData.citizenid
|
||||||
local issuerCitizenId = issuerPlayer.PlayerData.citizenid
|
local issuerCitizenId = issuerPlayer.PlayerData.citizenid
|
||||||
|
|
||||||
-- Check if license type is valid
|
-- Prüfen ob Lizenztyp gültig ist
|
||||||
if not Config.LicenseTypes[licenseData.license_type] then
|
if not Config.LicenseTypes[licenseData.license_type] then
|
||||||
TriggerClientEvent('QBCore:Notify', src, 'Ungültiger Lizenztyp!', 'error')
|
TriggerClientEvent('QBCore:Notify', src, 'Ungültiger Lizenztyp!', 'error')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Save photo if provided
|
-- Foto speichern falls vorhanden
|
||||||
if licenseData.photo_url then
|
if licenseData.photo_url then
|
||||||
-- Here you would save the photo to your storage system
|
|
||||||
-- For example, to a folder or database
|
|
||||||
-- This is just a placeholder
|
|
||||||
debugPrint("Foto für Lizenz vorhanden")
|
debugPrint("Foto für Lizenz vorhanden")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- First deactivate any existing licenses of this type
|
-- Alte Lizenzen deaktivieren
|
||||||
local deactivateQuery = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ?"
|
local deactivateQuery = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ?"
|
||||||
MySQL.query.await(deactivateQuery, {targetCitizenId, licenseData.license_type})
|
MySQL.query.await(deactivateQuery, {targetCitizenId, licenseData.license_type})
|
||||||
|
|
||||||
-- Insert into database with manual data
|
-- Klassen zu JSON konvertieren
|
||||||
|
local classesJson = json.encode(licenseData.classes or {})
|
||||||
|
|
||||||
|
-- In Datenbank einfügen mit manuellen Daten
|
||||||
local query = [[
|
local query = [[
|
||||||
INSERT INTO player_licenses
|
INSERT INTO player_licenses
|
||||||
(citizenid, license_type, name, birthday, gender, issue_date, expire_date, issued_by, is_active, photo_url, created_at)
|
(citizenid, license_type, name, birthday, gender, issue_date, expire_date, issued_by, is_active, classes, photo_url, notes, created_at)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local createdAt = os.time()
|
local createdAt = os.time()
|
||||||
|
@ -869,25 +869,27 @@ RegisterNetEvent('license-system:server:issueManualLicense', function(targetId,
|
||||||
licenseData.issue_date,
|
licenseData.issue_date,
|
||||||
licenseData.expire_date,
|
licenseData.expire_date,
|
||||||
issuerCitizenId,
|
issuerCitizenId,
|
||||||
|
classesJson,
|
||||||
licenseData.photo_url or '',
|
licenseData.photo_url or '',
|
||||||
|
licenseData.notes or '',
|
||||||
createdAt
|
createdAt
|
||||||
}
|
}
|
||||||
|
|
||||||
local result = MySQL.insert.await(query, insertData)
|
local result = MySQL.insert.await(query, insertData)
|
||||||
|
|
||||||
if result then
|
if result then
|
||||||
-- Invalidate cache
|
-- Cache invalidieren
|
||||||
invalidateCache(targetCitizenId)
|
invalidateCache(targetCitizenId)
|
||||||
|
|
||||||
local targetName = getPlayerName(targetId)
|
local targetName = getPlayerName(targetId)
|
||||||
local issuerName = getPlayerName(src)
|
local issuerName = getPlayerName(src)
|
||||||
local config = Config.LicenseTypes[licenseData.license_type]
|
local config = Config.LicenseTypes[licenseData.license_type]
|
||||||
|
|
||||||
-- Notifications
|
-- Benachrichtigungen
|
||||||
TriggerClientEvent('QBCore:Notify', src, 'Lizenz erfolgreich ausgestellt für ' .. targetName, 'success')
|
TriggerClientEvent('QBCore:Notify', src, 'Lizenz erfolgreich ausgestellt für ' .. targetName, 'success')
|
||||||
TriggerClientEvent('QBCore:Notify', targetId, 'Du hast eine neue Lizenz erhalten: ' .. config.label, 'success')
|
TriggerClientEvent('QBCore:Notify', targetId, 'Du hast eine neue Lizenz erhalten: ' .. config.label, 'success')
|
||||||
|
|
||||||
-- Events
|
-- Events senden
|
||||||
TriggerClientEvent('license-system:client:licenseIssued', src, targetId, licenseData.license_type)
|
TriggerClientEvent('license-system:client:licenseIssued', src, targetId, licenseData.license_type)
|
||||||
TriggerClientEvent('license-system:client:refreshMenu', src)
|
TriggerClientEvent('license-system:client:refreshMenu', src)
|
||||||
|
|
||||||
|
@ -898,6 +900,7 @@ RegisterNetEvent('license-system:server:issueManualLicense', function(targetId,
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
-- EVENT HANDLER: Alle Lizenzen eines Spielers anfordern (inkl. inaktive)
|
-- EVENT HANDLER: Alle Lizenzen eines Spielers anfordern (inkl. inaktive)
|
||||||
RegisterNetEvent('license-system:server:requestAllPlayerLicenses', function(targetId, includeInactive)
|
RegisterNetEvent('license-system:server:requestAllPlayerLicenses', function(targetId, includeInactive)
|
||||||
local src = source
|
local src = source
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue