Files
harheimertc/pages/mannschaften/spielplaene.vue
Torsten Schulz (local) 737c3064bd Initial commit: Harheimer TC Website
- Vue 3 + Nuxt 3 Framework
- Tailwind CSS Styling
- Responsive Design mit schwarz-roten Vereinsfarben
- Dynamische Galerie mit Lightbox
- Event-Management über CSV-Dateien
- Mannschaftsübersicht mit dynamischen Seiten
- SMTP-Kontaktformular
- Google Maps Integration
- Mobile-optimierte Navigation mit Submenus
- Trainer-Übersicht
- Vereinsmeisterschaften, Spielsysteme, TT-Regeln
- Impressum mit Datenschutzerklärung
2025-10-21 00:41:12 +02:00

269 lines
8.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="min-h-full py-16 bg-gray-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center mb-12">
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
Spielpläne
</h1>
<div class="w-24 h-1 bg-primary-600 mx-auto mb-6" />
<p class="text-xl text-gray-600 max-w-3xl mx-auto">
Aktuelle Spielpläne der Saison {{ aktuellesSaisonLabel }}
</p>
</div>
<!-- Spielpläne -->
<div v-if="spielplaene.length > 0" class="space-y-4 max-w-4xl mx-auto">
<div
v-for="(plan, index) in spielplaene"
:key="index"
class="bg-white rounded-xl shadow-lg border border-gray-100 p-6 hover:shadow-xl transition-shadow"
>
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center">
<FileText :size="24" class="text-primary-600" />
</div>
<div>
<h3 class="text-lg font-semibold text-gray-900">{{ plan.titel }}</h3>
<p class="text-sm text-gray-500">Saison {{ plan.saison }}</p>
</div>
</div>
<a
:href="plan.url"
download
class="inline-flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg transition-colors"
>
<Download :size="18" class="mr-2" />
Download
</a>
</div>
</div>
</div>
<!-- Keine Spielpläne -->
<div v-else class="text-center py-16 bg-white rounded-xl shadow-lg max-w-4xl mx-auto">
<FileText :size="48" class="text-gray-400 mx-auto mb-4" />
<h3 class="text-xl font-semibold text-gray-900 mb-2">Keine Spielpläne verfügbar</h3>
<p class="text-gray-600">
Für die aktuelle Saison {{ aktuellesSaisonLabel }} sind noch keine Spielpläne verfügbar.
</p>
</div>
<!-- Online Spielpläne und Tabellen -->
<div class="mt-12 max-w-4xl mx-auto">
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6 text-center">
Online Spielpläne & Tabellen
</h2>
<div v-if="mannschaftenMitLinks.length > 0" class="space-y-3">
<div
v-for="(mannschaft, index) in mannschaftenMitLinks"
:key="index"
class="bg-white rounded-lg shadow border border-gray-100 p-4 hover:shadow-md transition-shadow"
>
<div class="flex items-center justify-between">
<div>
<h3 class="font-semibold text-gray-900">{{ mannschaft.mannschaft }}</h3>
<p class="text-sm text-gray-500">{{ mannschaft.liga }}</p>
</div>
<a
:href="mannschaft.weitere_informationen_link"
target="_blank"
class="inline-flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors text-sm"
>
<ExternalLink :size="16" class="mr-2" />
Online ansehen
</a>
</div>
</div>
</div>
</div>
<!-- Info-Box -->
<div class="mt-12 max-w-4xl mx-auto bg-primary-50 border border-primary-100 rounded-xl p-6">
<h3 class="text-lg font-semibold text-primary-900 mb-2">
Hinweis
</h3>
<p class="text-primary-800">
Die Spielpläne werden automatisch für die aktuelle Saison angezeigt.
Ältere Spielpläne können auf Anfrage bereitgestellt werden.
</p>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { FileText, Download, ExternalLink } from 'lucide-vue-next'
const spielplaene = ref([])
const mannschaftenMitLinks = ref([])
// Berechne die aktuelle Saison
const aktuellesSaison = computed(() => {
const jetzt = new Date()
const monat = jetzt.getMonth() + 1 // 1-12
const jahr = jetzt.getFullYear()
// Saison wechselt im Juli/August
if (monat >= 7) {
return { start: jahr, ende: jahr + 1 }
} else {
return { start: jahr - 1, ende: jahr }
}
})
const aktuellesSaisonLabel = computed(() => {
return `${aktuellesSaison.value.start}/${aktuellesSaison.value.ende}`
})
// Funktion zum Extrahieren der Saison aus dem Dateinamen
const extractSaison = (filename) => {
console.log('extractSaison für:', filename)
// Normalisiere alle möglichen Trennzeichen zu einem einzigen Zeichen
// Suche nach 4 Ziffern, gefolgt von irgendeinem Nicht-Ziffer-Zeichen, gefolgt von 4 Ziffern
let match = filename.match(/(\d{4})[^0-9](\d{4})/)
if (match) {
const start = parseInt(match[1])
const ende = parseInt(match[2])
console.log(' Gefunden (4-stellig):', start, ende)
return { start, ende, label: `${start}/${ende}` }
}
// Suche nach 2 Ziffern, gefolgt von irgendeinem Nicht-Ziffer-Zeichen, gefolgt von 2 Ziffern
match = filename.match(/(\d{2})[^0-9](\d{2})/)
if (match) {
let start = parseInt(match[1])
let ende = parseInt(match[2])
// Wenn Kurzform (25-26), zu Langform konvertieren
if (start < 100) {
start = 2000 + start
ende = 2000 + ende
}
console.log(' Gefunden (2-stellig):', start, ende)
return { start, ende, label: `${start}/${ende}` }
}
console.log(' Keine Saison gefunden')
return null
}
// Prüfe, ob eine Saison zur aktuellen Saison passt
const istAktuellesSaison = (saison) => {
if (!saison) return false
return saison.start === aktuellesSaison.value.start &&
saison.ende === aktuellesSaison.value.ende
}
// Lade Spielpläne
const loadSpielplaene = async () => {
try {
console.log('=== SPIELPLÄNE LADEN ===')
console.log('Aktuelle Saison:', aktuellesSaison.value)
console.log('Saison Label:', aktuellesSaisonLabel.value)
// Lade Dateien vom Server
const response = await fetch('/api/spielplaene')
if (!response.ok) {
console.error('Fehler beim Laden der Spielpläne:', response.status)
return
}
const dateien = await response.json()
console.log('Geladene Dateien:', dateien)
const gefiltert = dateien
.map(filename => {
console.log('Verarbeite Datei:', filename)
const saison = extractSaison(filename)
console.log(' Extrahierte Saison:', saison)
console.log(' Ist aktuelle Saison?', saison ? istAktuellesSaison(saison) : false)
if (!saison || !istAktuellesSaison(saison)) {
return null
}
// Extrahiere Titel aus Dateiname
const titel = filename
.replace(/\.(pdf|PDF|xlsx|XLSX|xls|XLS)$/, '')
.replace(/[-_]/g, ' ')
.replace(/\d{2,4}[-_\/]\d{2,4}/, '')
.trim()
return {
filename,
titel: titel || filename,
saison: saison.label,
url: `/spielplaene/${filename}`
}
})
.filter(item => item !== null)
spielplaene.value = gefiltert
console.log('Aktuelle Saison:', aktuellesSaisonLabel.value)
console.log('Gefundene Spielpläne:', spielplaene.value)
} catch (error) {
console.error('Fehler beim Laden der Spielpläne:', error)
}
}
// Lade Mannschaften aus CSV
const loadMannschaften = async () => {
try {
const response = await fetch('/data/mannschaften.csv')
if (!response.ok) return
const csv = await response.text()
const lines = csv.split('\n').filter(line => line.trim() !== '')
if (lines.length < 2) return
mannschaftenMitLinks.value = lines.slice(1).map(line => {
// Besserer CSV-Parser: Respektiert Anführungszeichen
const values = []
let current = ''
let inQuotes = false
for (let i = 0; i < line.length; i++) {
const char = line[i]
if (char === '"') {
inQuotes = !inQuotes
} else if (char === ',' && !inQuotes) {
values.push(current.trim())
current = ''
} else {
current += char
}
}
values.push(current.trim())
if (values.length < 10) return null
return {
mannschaft: values[0].trim(),
liga: values[1].trim(),
weitere_informationen_link: values[8].trim()
}
}).filter(mannschaft => mannschaft !== null && mannschaft.weitere_informationen_link !== '')
console.log('Mannschaften mit Links:', mannschaftenMitLinks.value)
} catch (error) {
console.error('Fehler beim Laden der Mannschaften:', error)
}
}
onMounted(() => {
loadSpielplaene()
loadMannschaften()
})
useHead({
title: 'Spielpläne - Harheimer TC',
})
</script>