2026-07-10 00:54:40 +02:00
< template >
2026-07-10 22:28:26 +02:00
< div class = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12" >
< nav class = "text-sm mb-6" aria -label = " Breadcrumb " > < NuxtLink to = "/mietkatalog" style = "color: var(--secondary)" > ← Zurück zum Katalog < / NuxtLink > < / nav >
< div v-if = "loading" class="grid lg:grid-cols-2 gap-8" aria-live="polite" aria-busy="true"><div class="hms-skeleton aspect-square rounded-lg"></div><div class="space-y-4"><div class="hms-skeleton h-8 w-3/4"></div><div class="hms-skeleton h-4 w-1/4"></div><div class="hms-skeleton h-24 w-full"></div><div class="hms-skeleton h-32 w-full"></div><div class="hms-skeleton h-12 w-full" style="border-radius:var(--radius-md)" > < / div > < / div > < / div >
< ErrorState v-else-if = "error" title="Gerät nicht gefunden" message="Das angeforderte Gerät konnte nicht gefunden werden." @retry="navigate('/mietkatalog')" / >
< div v-else-if = "item" >
< div class = "grid lg:grid-cols-2 gap-8 lg:gap-12" >
< div class = "aspect-square rounded-lg flex items-center justify-center relative overflow-hidden border" : style = "{ background: 'var(--surface)', borderColor: 'var(--border)' }" >
< img v-if = "item.image" :src="item.image" :alt="item.name" class="absolute inset-0 w-full h-full object-cover" / >
< div v-else class = "text-center" > < div class = "text-8xl mb-2" style = "color: var(--secondary)" > 📦 < / div > < div class = "text-sm" style = "color: var(--secondary)" > Kein Bild verfügbar < / div > < / div >
< span class = "hms-badge hms-badge-primary absolute top-4 left-4 text-sm" > { { item . category } } < / span >
2026-07-10 00:54:40 +02:00
< / div >
2026-07-10 22:28:26 +02:00
< div >
< div class = "text-sm mb-1" style = "color: var(--secondary)" > Artikelnummer : { { item . code } } < / div >
< h1 class = "text-2xl sm:text-3xl font-bold mb-2" style = "color: var(--text)" > { { item . name } } < / h1 >
< div class = "text-sm mb-4" style = "color: var(--text-muted)" > Marke : < span class = "font-medium" style = "color: var(--text)" > { { item . brand } } < / span > < / div >
< p class = "leading-relaxed mb-6" style = "color: var(--text-muted)" > { { item . description } } < / p >
< div class = "hms-card p-4 mb-6" > < h2 class = "text-sm font-semibold mb-3" style = "color: var(--text)" > Technische Daten < / h2 > < dl class = "divide-y" : style = "{ borderColor: 'var(--border)' }" > < div v-for = "(value, key) in item.specs" :key="key" class="flex justify-between py-2 text-sm" :style="{ borderColor: 'var(--border)' }"><dt class="capitalize" style="color: var(--secondary)">{{ key.replace(/_/g, ' ') }}</dt><dd class="font-medium text-right" style="color: var(--text)" > {{ value }} < / dd > < / div > < / dl > < / div >
< div class = "hms-card p-6" >
< h2 class = "text-sm font-semibold mb-4" style = "color: var(--text)" > Mietanfrage < / h2 >
< div class = "grid grid-cols-2 gap-3 mb-4" > < div > < label for = "rental-start" class = "block text-xs font-medium mb-1" style = "color: var(--secondary)" > Mietbeginn < / label > < input id = "rental-start" v-model = "rentalStart" type="date" class="hms-input text-sm" /></div><div><label for="rental-end" class="block text-xs font-medium mb-1" style="color: var(--secondary)">Mietende</label><input id="rental-end" v-model="rentalEnd" type="date" class="hms-input text-sm" / > < / div > < / div >
< div class = "mb-4" > < label for = "quantity" class = "block text-xs font-medium mb-1" style = "color: var(--secondary)" > Anzahl < / label > < div class = "flex items-center gap-3" > < button @click ="quantity = Math.max(1, quantity - 1)" class = "hms-btn hms-btn-secondary px-3 py-2" aria -label = " Anzahl verringern " > − < / button > < input id = "quantity" v -model .number = " quantity " type = "number" min = "1" class = "hms-input text-center w-20" aria -label = " Anzahl " / > < button @click ="quantity = quantity + 1" class = "hms-btn hms-btn-secondary px-3 py-2" aria -label = " Anzahl erhöhen " > + < / button > < / div > < / div >
< button @click ="addToCart" class = "hms-btn hms-btn-primary w-full py-3 text-base" > < svg class = "w-5 h-5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path stroke -linecap = " round " stroke -linejoin = " round " stroke -width = " 2 " d = "M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" / > < / svg > Zur Mietanfrage hinzufügen < / button >
< p class = "text-xs mt-3 text-center" style = "color: var(--secondary)" > Preise auf Anfrage – unverbindliche Mietanfrage < / p >
2026-07-10 00:54:40 +02:00
< / div >
< / div >
< / div >
2026-07-10 22:28:26 +02:00
< section v-if = "relatedItems.length" class="mt-16" aria-labelledby="related-title"><h2 id="related-title" class="text-xl font-semibold mb-6" style="color: var(--text)">Ähnliche Geräte</h2><div class="grid grid-cols-1 sm:grid-cols-3 gap-6"><EquipmentCard v-for="ri in relatedItems" :key="ri.id" :item="ri" @click="navigate('/mietkatalog/' + ri.id)" @add-to-cart="addToCartSimple" / > < / div > < / section >
< / div >
2026-07-10 00:54:40 +02:00
< / div >
< / template >
< script setup lang = "ts" >
2026-07-10 22:28:26 +02:00
import { ref , computed , onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useCart } from '~/composables/useCart'
const route = useRoute ( )
const { addItemByFields } = useCart ( )
const loading = ref ( true )
const error = ref ( false )
const quantity = ref ( 1 )
const rentalStart = ref ( '' )
const rentalEnd = ref ( '' )
const item = ref < any > ( null )
const equipmentData = [
{ id : 1 , code : 'LT-001' , name : 'L-Acoustics K2' , category : 'Tontechnik' , description : 'Das L-Acoustics K2 ist das Flaggschiff der Line-Array-Serie und eignet sich für große Open-Air-Veranstaltungen und Hallenbeschallung.' , brand : 'L-Acoustics' , specs : { weight : '56 kg' , power : '1440 W' , freq _range : '35 Hz - 20 kHz' , max _spl : '142 dB' , coverage : '10°-110° variable' } , image : '' , related : [ 2 , 4 , 3 ] } ,
{ id : 2 , code : 'LT-002' , name : 'd&b audiotechnik KSL8' , category : 'Tontechnik' , description : 'Bi-amplified Column Array Loudspeaker mit 80° horizontaler Abstrahlung.' , brand : 'd&b audiotechnik' , specs : { weight : '32 kg' , power : '1200 W' , freq _range : '55 Hz - 18 kHz' , max _spl : '138 dB' , coverage : '80° horizontal' } , image : '' , related : [ 1 , 4 , 18 ] } ,
{ id : 3 , code : 'LT-003' , name : 'Shure SM58' , category : 'Tontechnik' , description : 'Das weltweit meistverkaufte dynamische Gesangsmikrofon.' , brand : 'Shure' , specs : { weight : '330 g' , type : 'dynamisch' , polar : 'Kardioid' , freq _range : '50 Hz - 15 kHz' , connector : 'XLR3' } , image : '' , related : [ 4 , 18 , 1 ] } ,
{ id : 4 , code : 'LT-004' , name : 'Allen & Heath dLive S5000' , category : 'Tontechnik' , description : 'Professionelles digitales Mischpult mit 96 Input Fadern und 64 Mix Buses.' , brand : 'Allen & Heath' , specs : { channels : '96' , buses : '64' , fx : '16 Effekt-Engines' , screens : '2x 15" Touch' , i _o : '128x128 Dante' } , image : '' , related : [ 1 , 2 , 3 ] } ,
{ id : 5 , code : 'LL-001' , name : 'Robe Pointe' , category : 'Lichttechnik' , description : '230W Moving Beam mit 5°-20° Zoom und 16-bit Dimming.' , brand : 'Robe' , specs : { power : '230 W' , source : 'MSD 230' , zoom : '5°-20°' , dimming : '16-bit' , pan : '540°' , tilt : '270°' } , image : '' , related : [ 6 , 7 , 8 ] } ,
{ id : 6 , code : 'LL-002' , name : 'Mac Aura PXL' , category : 'Lichttechnik' , description : 'RGBW Wash-Light mit 18 einzelnen pixel-mappable Zellen.' , brand : 'Martin' , specs : { power : '700 W' , cells : '18' , zoom : '4°-60°' , control : 'DMX 512, Art-Net' , color : 'RGBW' } , image : '' , related : [ 5 , 7 , 8 ] } ,
{ id : 7 , code : 'LL-003' , name : 'Showtec Phantom 140' , category : 'Lichttechnik' , description : '140W LED Spot Moving Head mit 9 rotierenden und 9 festen Gobos.' , brand : 'Showtec' , specs : { power : '140 W' , gobos : '9 rotierend + 9 fest' , zoom : '12°-18°' , color : '7+1 Farbrad' , prism : '8-fach rotierend' } , image : '' , related : [ 5 , 6 , 8 ] } ,
{ id : 8 , code : 'LL-004' , name : 'Astera Titan Tube' , category : 'Lichttechnik' , description : 'Pixel Tube 1m Länge, batteriebetrieben mit 20 Std. Laufzeit.' , brand : 'Astera' , specs : { length : '1015 mm' , battery : '20 Std' , cells : '16 Pixel' , control : 'DMX, CRMX, App' , color : 'RGBW' } , image : '' , related : [ 5 , 6 , 7 ] } ,
{ id : 9 , code : 'RG-001' , name : 'Tomcat Truss 290' , category : 'Rigging' , description : 'Aluminium Traverse 4-Punkt, 290mm Profil, 2m Länge.' , brand : 'Tomcat' , specs : { profile : '290x290 mm' , length : '2 m' , load : '450 kg' , material : 'Aluminium EN AW-6082' } , image : '' , related : [ 10 , 14 , 15 ] } ,
{ id : 10 , code : 'RG-002' , name : 'Chain Motor 1T' , category : 'Rigging' , description : 'Bühnen-Motor 1000kg Tragkraft, D8+ Plus geprüft.' , brand : 'Verlinde' , specs : { capacity : '1000 kg' , speed : '4-8 m/min' , control : 'Direct Control' , certification : 'D8+ Plus' } , image : '' , related : [ 9 , 14 , 13 ] } ,
{ id : 11 , code : 'VD-001' , name : 'LED Video Wall P3.9' , category : 'Video' , description : 'Indoor LED Panel P3.9, 500x500mm, 3840Hz Refresh Rate.' , brand : 'Absen' , specs : { pixel _pitch : '3.9 mm' , size : '500x500 mm' , refresh : '3840 Hz' , brightness : '1500 nits' , ip : 'IP30 Indoor' } , image : '' , related : [ 12 , 5 , 6 ] } ,
{ id : 12 , code : 'VD-002' , name : 'Blackmagic ATEM Mini Extreme' , category : 'Video' , description : '8-Input HDMI Switcher mit ISO Recording und Multiview.' , brand : 'Blackmagic' , specs : { inputs : '8x HDMI' , outputs : '2x HDMI' , recording : 'ISO Recording' , streaming : 'Direct Streaming' , audio : '2x 3.5mm' } , image : '' , related : [ 11 , 5 , 7 ] } ,
{ id : 13 , code : 'ST-001' , name : 'WAGO 24V 40A Netzteilkasten' , category : 'Strom' , description : '24V DC 40A Netzteil in Flightcase mit 4x Schuko Ausgang.' , brand : 'WAGO' , specs : { output : '24V DC 40A' , inputs : '4x Schuko' , protection : 'IP54' , cooling : 'Forced Air' } , image : '' , related : [ 14 , 10 , 9 ] } ,
{ id : 14 , code : 'ST-002' , name : 'Duraplex 32A Stromverteiler' , category : 'Strom' , description : '32A 5-polig auf 3x 16A + 3x Schuko mit FI-Schutzschalter.' , brand : 'Duraplex' , specs : { input : '32A 5-pol CEE' , outputs : '3x 16A + 3x Schuko' , protection : 'FI/A' , cable : 'H07BQ-F 5G6' } , image : '' , related : [ 13 , 10 , 9 ] } ,
{ id : 15 , code : 'ZB-001' , name : 'Flightcase 19" 12HE' , category : 'Zubehör' , description : '19" Rack Flightcase 12HE mit Front- und Rücktür.' , brand : 'Thon' , specs : { rack _units : '12 HE' , depth : '600 mm' , wheels : '4x 100mm' , material : 'Birkenholz + Alu-Kanten' } , image : '' , related : [ 16 , 4 , 15 ] } ,
{ id : 16 , code : 'ZB-002' , name : 'XLR Kabel 20m' , category : 'Zubehör' , description : 'XLR3 male/female Mikrofonkabel, 20m, Neutrik Stecker.' , brand : 'Tasker' , specs : { length : '20 m' , connectors : 'XLR3 M/F' , shielding : 'double' , cable : 'Tasker C118' } , image : '' , related : [ 3 , 18 , 4 ] } ,
{ id : 17 , code : 'ZB-003' , name : 'DJ-Table Pro' , category : 'Zubehör' , description : 'Mobile DJ-Tisch mit Laptop-Ständer und LED-Beleuchtung.' , brand : 'Stage Traps' , specs : { width : '120 cm' , height : '95 cm' , features : 'LED, Laptop-Ständer' , weight : '22 kg' } , image : '' , related : [ 12 , 5 , 15 ] } ,
{ id : 18 , code : 'LT-005' , name : 'Sennheiser EW-DX 835' , category : 'Tontechnik' , description : 'Digitales Funkmikrofon-Set mit Handheld und Empfänger.' , brand : 'Sennheiser' , specs : { type : 'Digital Wireless' , range : '100 m' , battery : '12 Std' , freq _range : '563-608 MHz' , channels : 'gleichzeitig 95' } , image : '' , related : [ 3 , 4 , 16 ] }
]
const relatedItems = computed ( ( ) => {
if ( ! item . value || ! item . value . related ) return [ ]
return item . value . related . map ( ( id : number ) => equipmentData . find ( e => e . id === id ) ) . filter ( Boolean )
} )
onMounted ( ( ) => {
setTimeout ( ( ) => {
const found = equipmentData . find ( e => e . id === Number ( route . params . id ) )
if ( found ) { item . value = found } else { error . value = true }
loading . value = false
} , 800 )
} )
function navigate ( route : string ) {
navigateTo ( route )
if ( import . meta . client ) window . scrollTo ( 0 , 0 )
2026-07-10 00:54:40 +02:00
}
2026-07-10 22:28:26 +02:00
function addToCart ( ) {
addItemByFields ( {
equipment _id : item . value . id ,
name : item . value . name ,
rental _price : null ,
image _url : item . value . image || null
} )
navigate ( '/warenkorb' )
2026-07-10 00:54:40 +02:00
}
2026-07-10 22:28:26 +02:00
function addToCartSimple ( e : any ) {
2026-07-10 01:32:19 +02:00
addItemByFields ( {
2026-07-10 22:28:26 +02:00
equipment _id : e . id ,
name : e . name ,
rental _price : null ,
image _url : e . image || null
} )
2026-07-10 00:54:40 +02:00
}
< / script >