From 70d82f567014f4fb0f4d6e02996cac5905e36021 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 15 Apr 2026 21:10:01 +0200 Subject: [PATCH] Auto-sync 2026-04-15 21:10 --- [core]/mercyv-garage/nui/script.js | 40 ++++++++++++++++++++++------ [core]/mercyv-garage/nui/style.css | 30 +++++++++++++++++++++ [core]/mercyv-garage/server/main.lua | 10 +++++-- 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/[core]/mercyv-garage/nui/script.js b/[core]/mercyv-garage/nui/script.js index d0cba3f9..0e6d1f81 100644 --- a/[core]/mercyv-garage/nui/script.js +++ b/[core]/mercyv-garage/nui/script.js @@ -12,12 +12,12 @@ const app = new Vue({ deleteConfirmId: null, capturingField: null, windowWidth: window.innerWidth, posFields: [ - { field: 'npc', label: 'NPC Position', hasHeading: true }, - { field: 'spawn', label: 'Spawn Position (Fahrzeug erscheint)',hasHeading: true }, - { field: 'park', label: 'Einpark-Zone (Marker am Boden)', hasHeading: false }, - { field: 'showcar', label: 'Vorschau-Fahrzeug Position', hasHeading: true }, - { field: 'cam', label: 'Kamera Position', hasHeading: false }, + { field: 'npc', label: 'NPC Position', hasHeading: true }, + { field: 'spawn', label: 'Spawn Position (Fahrzeug erscheint)', hasHeading: true }, + { field: 'park', label: 'Einpark-Zone (Marker am Boden)', hasHeading: false }, ], + jobVehicles: [], // Fahrzeuge für die aktuelle Jobgarage + newJobVehicle: '', // Eingabe: neues Modell }, computed: { @@ -107,9 +107,18 @@ const app = new Vue({ }); }, newGarage() { - this.editingGarage = { _isNew: true, id:'', label:'', type:'normal', access:'none', gang:'none', npc_model:'a_m_m_prolhost_01', blip_show:1, blip_show_bool:true, blip_type:357, blip_colour:3, npc_x:0,npc_y:0,npc_z:0,npc_heading:0, spawn_x:0,spawn_y:0,spawn_z:0,spawn_heading:0, park_x:0,park_y:0,park_z:0,park_heading:0, showcar_x:null,showcar_y:null,showcar_z:null,showcar_heading:0, cam_x:null,cam_y:null,cam_z:null,cam_rot_z:-20 }; + this.editingGarage = { _isNew: true, id:'', label:'', type:'normal', access:'none', gang:'none', npc_model:'a_m_m_prolhost_01', blip_show:1, blip_show_bool:true, blip_type:357, blip_colour:3, npc_x:0,npc_y:0,npc_z:0,npc_heading:0, spawn_x:0,spawn_y:0,spawn_z:0,spawn_heading:0, park_x:0,park_y:0,park_z:0,park_heading:0 }; + this.jobVehicles = []; + }, + editGarage(g) { + this.editingGarage = Object.assign({ _isNew: false, blip_show_bool: g.blip_show == 1 }, g); + // Job-Fahrzeuge laden falls Jobgarage + if (g.type === 'jobgarage') { + this.jobVehicles = g.job_vehicles ? [...g.job_vehicles] : []; + } else { + this.jobVehicles = []; + } }, - editGarage(g) { this.editingGarage = Object.assign({ _isNew: false, blip_show_bool: g.blip_show == 1 }, g); }, confirmDelete(id) { this.deleteConfirmId = id; }, deleteGarage() { if (!this.deleteConfirmId) return; @@ -118,6 +127,18 @@ const app = new Vue({ if (this.editingGarage && this.editingGarage.id === this.deleteConfirmId) this.editingGarage = null; this.deleteConfirmId = null; }, + // Job-Fahrzeug hinzufügen + addJobVehicle() { + const model = this.newJobVehicle.trim().toLowerCase(); + if (!model) return; + if (!this.jobVehicles.find(v => v.model === model)) { + this.jobVehicles.push({ model, label: model.toUpperCase() }); + } + this.newJobVehicle = ''; + }, + removeJobVehicle(index) { + this.jobVehicles.splice(index, 1); + }, saveGarage() { const g = this.editingGarage; if (!g) return; @@ -127,6 +148,9 @@ const app = new Vue({ const payload = Object.assign({}, g); delete payload._isNew; delete payload.blip_show_bool; payload.blip_show = g.blip_show_bool ? 1 : 0; + if (g.type === 'jobgarage') { + payload.job_vehicles = this.jobVehicles; + } $.post(`https://${GetParentResourceName()}/adminSaveGarage`, JSON.stringify(payload)); const i = this.adminGarages.findIndex(x => x.id === payload.id); if (i >= 0) this.adminGarages.splice(i, 1, payload); else this.adminGarages.push(payload); @@ -139,7 +163,7 @@ const app = new Vue({ $.post(`https://${GetParentResourceName()}/startCapture`, JSON.stringify({ field })); }, getFieldLabel(field) { - const l = { npc:'NPC Position', spawn:'Spawn Position', park:'Einpark-Zone', showcar:'Vorschau-Fahrzeug', cam:'Kamera' }; + const l = { npc:'NPC Position', spawn:'Spawn Position', park:'Einpark-Zone' }; return l[field] || field; }, getTypeIcon(type) { diff --git a/[core]/mercyv-garage/nui/style.css b/[core]/mercyv-garage/nui/style.css index fea86584..91bb0273 100644 --- a/[core]/mercyv-garage/nui/style.css +++ b/[core]/mercyv-garage/nui/style.css @@ -507,3 +507,33 @@ kbd { } .mv-parkin-btn:hover { background: rgba(232,131,10,0.28); } .mv-parkin-btn:active { transform: scale(0.98); } + +/* Job-Fahrzeuge Admin */ +.mv-job-vehicle-list { + display: flex; flex-direction: column; gap: 6px; + margin-bottom: 10px; +} +.mv-job-vehicle-item { + display: flex; align-items: center; justify-content: space-between; + background: rgba(255,255,255,0.04); + border: 1px solid rgba(255,255,255,0.08); + border-radius: 6px; padding: 8px 12px; +} +.mv-job-vehicle-name { + font-size: 13px; color: var(--text-secondary); +} +.mv-job-vehicle-name i { color: var(--accent); margin-right: 6px; } +.mv-job-vehicle-empty { + font-size: 12px; color: var(--text-muted); + padding: 8px; text-align: center; +} +.mv-job-vehicle-add { + display: flex; gap: 8px; align-items: center; +} +.mv-job-input { + flex: 1; padding: 8px 12px; + background: var(--bg-input); border: 1px solid var(--border); + border-radius: 8px; color: var(--text-secondary); + font-size: 13px; font-family: inherit; outline: none; +} +.mv-job-input:focus { border-color: var(--accent); } diff --git a/[core]/mercyv-garage/server/main.lua b/[core]/mercyv-garage/server/main.lua index adbd7497..81a3d692 100644 --- a/[core]/mercyv-garage/server/main.lua +++ b/[core]/mercyv-garage/server/main.lua @@ -375,9 +375,9 @@ RegisterNetEvent('mercyv-garage:getVehicles', function(garageId) Config.ServerNotification(src, Config.Notify.NO_ACCESS, "error") return end - -- Job-Fahrzeuge aus Config.JobVehicles + -- Job-Fahrzeuge: erst aus GaragesData (admin-gesetzt), dann Config.JobVehicles local jobCars = {} - local jobList = Config.JobVehicles and Config.JobVehicles[g.access] or {} + local jobList = (Config.JobVehicles and Config.JobVehicles[g.access]) or {} for i, car in ipairs(jobList) do table.insert(jobCars, { plate = car.model, @@ -601,6 +601,12 @@ RegisterNetEvent('mercyv-garage:admin:saveGarage', function(data) showcar_x=data.showcar_x,showcar_y=data.showcar_y,showcar_z=data.showcar_z,showcar_heading=data.showcar_heading or 0, cam_x=data.cam_x,cam_y=data.cam_y,cam_z=data.cam_z,cam_rot_z=data.cam_rot_z or -20, }) + -- Job-Fahrzeuge in Config aktualisieren + if data.type == 'jobgarage' and data.job_vehicles then + if not Config.JobVehicles then Config.JobVehicles = {} end + Config.JobVehicles[data.access] = data.job_vehicles + end + BroadcastGarages() Config.ServerNotification(src, Config.Notify.ADMIN_SAVED, "success") end)