678 lines
24 KiB
Vue
678 lines
24 KiB
Vue
<template>
|
|
<div class="min-h-full py-16 bg-gray-50">
|
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div
|
|
v-if="mannschaft"
|
|
class="space-y-8"
|
|
>
|
|
<!-- Header -->
|
|
<div class="bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
|
<h1 class="text-4xl font-display font-bold mb-2">
|
|
{{ mannschaft.mannschaft }}
|
|
</h1>
|
|
<p class="text-primary-100 text-xl">
|
|
{{ mannschaft.liga }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Liga-Info -->
|
|
<div class="bg-white rounded-xl shadow-lg p-6">
|
|
<h2 class="text-2xl font-semibold text-gray-900 mb-6">
|
|
Liga-Informationen
|
|
</h2>
|
|
<div class="grid md:grid-cols-2 gap-6">
|
|
<div class="space-y-4">
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
|
<span class="text-gray-600">Staffelleiter:</span>
|
|
<span class="font-semibold text-gray-900">{{ mannschaft.staffelleiter }}</span>
|
|
</div>
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
|
<span class="text-gray-600">Telefon:</span>
|
|
<span class="font-semibold text-gray-900">{{ mannschaft.telefon }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="space-y-4">
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
|
<span class="text-gray-600">Heimspieltag:</span>
|
|
<span class="font-semibold text-gray-900">{{ mannschaft.heimspieltag }}</span>
|
|
</div>
|
|
<div class="flex items-center space-x-3">
|
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
|
<span class="text-gray-600">Spielsystem:</span>
|
|
<span class="font-semibold text-gray-900">{{ mannschaft.spielsystem }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mannschaftsaufstellung -->
|
|
<div class="bg-white rounded-xl shadow-lg p-6">
|
|
<h2 class="text-2xl font-semibold text-gray-900 mb-6">
|
|
Mannschaftsaufstellung Saison 2025/26
|
|
</h2>
|
|
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<div
|
|
v-for="(spieler, index) in getSpielerListe(mannschaft)"
|
|
:key="index"
|
|
class="bg-gray-50 rounded-lg p-4 text-center"
|
|
:class="spieler === mannschaft.mannschaftsfuehrer ? 'ring-2 ring-primary-500 bg-primary-50' : ''"
|
|
>
|
|
<div class="font-semibold text-gray-900">
|
|
{{ spieler }}
|
|
</div>
|
|
<div
|
|
v-if="spieler === mannschaft.mannschaftsfuehrer"
|
|
class="text-xs text-primary-600 font-medium mt-1"
|
|
>
|
|
Mannschaftsführer
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Aktueller Spielplan -->
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
<div>
|
|
<h2 class="text-2xl font-semibold text-gray-900">
|
|
Aktueller Spielplan
|
|
</h2>
|
|
<p
|
|
v-if="spielplanSeasonLabel"
|
|
class="text-sm text-gray-600 mt-1"
|
|
>
|
|
Saison {{ spielplanSeasonLabel }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="inline-flex rounded-lg border border-gray-200 p-1 bg-gray-50">
|
|
<button
|
|
type="button"
|
|
class="px-4 py-2 text-sm font-medium rounded-md transition-colors"
|
|
:class="activePanelTab === 'matches' ? 'bg-white text-primary-700 shadow-sm' : 'text-gray-600 hover:text-gray-900'"
|
|
@click="activePanelTab = 'matches'"
|
|
>
|
|
Matches
|
|
</button>
|
|
<button
|
|
v-if="hasTableLink"
|
|
type="button"
|
|
class="px-4 py-2 text-sm font-medium rounded-md transition-colors"
|
|
:class="activePanelTab === 'table' ? 'bg-white text-primary-700 shadow-sm' : 'text-gray-600 hover:text-gray-900'"
|
|
@click="activePanelTab = 'table'"
|
|
>
|
|
Tabelle
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="activePanelTab === 'matches' && isSpielplanLoading"
|
|
class="p-6 text-sm text-gray-600"
|
|
>
|
|
Spielplan wird geladen...
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="activePanelTab === 'matches' && spielplanError"
|
|
class="p-6 text-sm text-red-600"
|
|
>
|
|
{{ spielplanError }}
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="activePanelTab === 'matches' && mannschaftSpielplan.length === 0"
|
|
class="p-6 text-sm text-gray-600"
|
|
>
|
|
Für diese Mannschaft sind im aktuellen Spielplan keine Spiele vorhanden.
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="activePanelTab === 'matches'"
|
|
class="overflow-x-auto"
|
|
>
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Termin
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Heim
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Gast
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Ergebnis
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Runde
|
|
</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Gruppe
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
<tr
|
|
v-for="game in mannschaftSpielplan"
|
|
:key="`${game.Termin}-${game.HeimMannschaft}-${game.GastMannschaft}`"
|
|
:class="getRowClass(game)"
|
|
>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
{{ game.Termin || '-' }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-medium">
|
|
{{ game.HeimMannschaft || '-' }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-medium">
|
|
{{ game.GastMannschaft || '-' }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
{{ formatResult(game) }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
{{ formatRunde(game.Runde) }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
<span class="text-xs leading-tight text-gray-700">
|
|
<span class="block">
|
|
{{ game.Altersklasse || '-' }}
|
|
</span>
|
|
<span class="block text-gray-500">
|
|
{{ formatStaffel(game.Staffel) }}
|
|
</span>
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div
|
|
v-if="activePanelTab === 'table' && isTableLoading"
|
|
class="p-6 text-sm text-gray-600"
|
|
>
|
|
Tabelle wird geladen...
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="activePanelTab === 'table' && tableError"
|
|
class="p-6 text-sm text-red-600"
|
|
>
|
|
{{ tableError }}
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="activePanelTab === 'table' && teamTableRows.length === 0"
|
|
class="p-6 text-sm text-gray-600"
|
|
>
|
|
Für diese Mannschaft ist aktuell keine Tabelle hinterlegt.
|
|
</div>
|
|
|
|
<div
|
|
v-else-if="activePanelTab === 'table'"
|
|
class="overflow-x-auto"
|
|
>
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Platz
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Mannschaft
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Spiele
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
S/U/N
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Sätze
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Bälle
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Punkte
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
<tr
|
|
v-for="(row, index) in teamTableRows"
|
|
:key="`${row.team_id || row.team_name || 'row'}-${index}`"
|
|
:class="isCurrentTeamRow(row) ? 'bg-primary-50' : 'bg-white'"
|
|
>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
|
{{ row.table_rank ?? '-' }}
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900 font-medium">
|
|
{{ row.team_name || '-' }}
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
|
{{ row.meetings_count ?? '-' }}
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
|
{{ formatSun(row) }}
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
|
{{ row.sets_relation || '-' }}
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
|
{{ row.games_relation || '-' }}
|
|
</td>
|
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
|
{{ formatPunkte(row) }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Links -->
|
|
<div class="bg-white rounded-xl shadow-lg p-6">
|
|
<h2 class="text-2xl font-semibold text-gray-900 mb-6">
|
|
Weitere Informationen
|
|
</h2>
|
|
<div class="text-center">
|
|
<a
|
|
v-if="mannschaft.weitere_informationen_link && mannschaft.weitere_informationen_link !== ''"
|
|
:href="mannschaft.weitere_informationen_link"
|
|
target="_blank"
|
|
class="inline-flex items-center px-8 py-4 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
|
>
|
|
<BarChart
|
|
:size="24"
|
|
class="mr-3"
|
|
/>
|
|
Weitere Informationen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Letzte Aktualisierung -->
|
|
<div class="bg-white rounded-xl shadow-lg p-6">
|
|
<p class="text-sm text-gray-500 text-center">
|
|
Zuletzt aktualisiert am: {{ formatDate(mannschaft.letzte_aktualisierung) }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Zurück-Button -->
|
|
<div class="text-center">
|
|
<NuxtLink
|
|
to="/mannschaften"
|
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
|
>
|
|
← Zurück zur Übersicht
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-else
|
|
class="text-center py-16"
|
|
>
|
|
<h1 class="text-4xl font-display font-bold text-gray-900 mb-4">
|
|
Mannschaft nicht gefunden
|
|
</h1>
|
|
<p class="text-gray-600 mb-8">
|
|
Die angeforderte Mannschaft konnte nicht gefunden werden.
|
|
</p>
|
|
<NuxtLink
|
|
to="/mannschaften"
|
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
|
>
|
|
Zur Mannschaftsübersicht
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { Users } from 'lucide-vue-next'
|
|
|
|
const route = useRoute()
|
|
const mannschaft = ref(null)
|
|
const mannschaftSpielplan = ref([])
|
|
const spielplanSeason = ref('')
|
|
const isSpielplanLoading = ref(false)
|
|
const spielplanError = ref('')
|
|
const activePanelTab = ref('matches')
|
|
const isTableLoading = ref(false)
|
|
const tableError = ref('')
|
|
const teamTableRows = ref([])
|
|
|
|
const hasTableLink = computed(() => {
|
|
const link = String(mannschaft.value?.weitere_informationen_link || '').trim()
|
|
return link.includes('/tabelle/')
|
|
})
|
|
|
|
const spielplanSeasonLabel = computed(() => {
|
|
const match = String(spielplanSeason.value || '').match(/^(\d{2})--(\d{2})$/)
|
|
return match ? `20${match[1]}/${match[2]}` : ''
|
|
})
|
|
|
|
async function fetchCsvText(url) {
|
|
const attempt = async () => {
|
|
const withBuster = `${url}${url.includes('?') ? '&' : '?'}_t=${Date.now()}`
|
|
const res = await fetch(withBuster, { cache: 'no-store' })
|
|
if (!res.ok) return null
|
|
return await res.text()
|
|
}
|
|
|
|
try {
|
|
return await attempt()
|
|
} catch (_e) {
|
|
await new Promise(resolve => setTimeout(resolve, 150))
|
|
return await attempt()
|
|
}
|
|
}
|
|
|
|
const loadMannschaften = async () => {
|
|
try {
|
|
const csv = await fetchCsvText('/api/mannschaften')
|
|
if (!csv) return
|
|
const lines = csv.split('\n').filter(line => line.trim() !== '')
|
|
|
|
if (lines.length < 2) return
|
|
|
|
const mannschaften = 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(),
|
|
staffelleiter: values[2].trim(),
|
|
telefon: values[3].trim(),
|
|
heimspieltag: values[4].trim(),
|
|
spielsystem: values[5].trim(),
|
|
mannschaftsfuehrer: values[6].trim(),
|
|
spieler: values[7].trim(),
|
|
weitere_informationen_link: values[8].trim(),
|
|
letzte_aktualisierung: values[9].trim(),
|
|
slug: values[0].trim().toLowerCase().replace(/\s+/g, '-')
|
|
}
|
|
}).filter(mannschaft => mannschaft !== null)
|
|
|
|
// Finde die Mannschaft basierend auf dem Slug
|
|
const currentSlug = route.params.slug
|
|
mannschaft.value = mannschaften.find(m => m.slug === currentSlug) || null
|
|
|
|
if (mannschaft.value) {
|
|
useHead({
|
|
title: `${mannschaft.value.mannschaft} - Harheimer TC`,
|
|
})
|
|
await Promise.all([loadSpielplan(), loadTeamTable()])
|
|
}
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Mannschaften:', error)
|
|
}
|
|
}
|
|
|
|
const loadTeamTable = async () => {
|
|
if (!mannschaft.value) return
|
|
|
|
if (!hasTableLink.value) {
|
|
teamTableRows.value = []
|
|
tableError.value = ''
|
|
return
|
|
}
|
|
|
|
isTableLoading.value = true
|
|
tableError.value = ''
|
|
|
|
try {
|
|
const params = new URLSearchParams({ team: mannschaft.value.mannschaft })
|
|
if (spielplanSeason.value) {
|
|
params.set('season', spielplanSeason.value)
|
|
}
|
|
|
|
const response = await fetch(`/api/spielplan/table?${params.toString()}`)
|
|
const result = await response.json()
|
|
|
|
if (!result.success) {
|
|
tableError.value = result.message || 'Tabelle konnte nicht geladen werden.'
|
|
teamTableRows.value = []
|
|
return
|
|
}
|
|
|
|
teamTableRows.value = Array.isArray(result?.table?.table?.leagueTable)
|
|
? result.table.table.leagueTable
|
|
: []
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Tabelle:', error)
|
|
tableError.value = 'Tabelle konnte nicht geladen werden.'
|
|
teamTableRows.value = []
|
|
} finally {
|
|
isTableLoading.value = false
|
|
}
|
|
}
|
|
|
|
const getTeamVariants = (cmsMannschaft) => {
|
|
const mannschaftMapping = {
|
|
'Erwachsene 1': ['harheimer tc'],
|
|
'Erwachsene 2': ['harheimer tc ii'],
|
|
'Erwachsene 3': ['harheimer tc iii'],
|
|
'Erwachsene 4': ['harheimer tc iv'],
|
|
'Erwachsene 5': ['harheimer tc v'],
|
|
'Jugendmannschaft': ['harheimer tc']
|
|
}
|
|
|
|
return mannschaftMapping[cmsMannschaft] || []
|
|
}
|
|
|
|
const isExactHarheimTeam = (teamName, variant) => {
|
|
if (variant === 'harheimer tc') {
|
|
return teamName === 'harheimer tc' ||
|
|
(teamName.startsWith('harheimer tc ') && !teamName.match(/harheimer tc\s+[ivx]+/i))
|
|
}
|
|
|
|
return teamName === variant || teamName.startsWith(`${variant} `)
|
|
}
|
|
|
|
const isSpielForMannschaft = (row, cmsMannschaft) => {
|
|
const variants = getTeamVariants(cmsMannschaft)
|
|
if (!variants.length) return false
|
|
|
|
const heimMannschaft = (row.HeimMannschaft || '').toLowerCase()
|
|
const gastMannschaft = (row.GastMannschaft || '').toLowerCase()
|
|
const heimAltersklasse = (row.HeimMannschaftAltersklasse || '').toLowerCase()
|
|
const gastAltersklasse = (row.GastMannschaftAltersklasse || '').toLowerCase()
|
|
const isHarheimerHeim = heimMannschaft.includes('harheimer tc')
|
|
const isHarheimerGast = gastMannschaft.includes('harheimer tc')
|
|
|
|
if (!isHarheimerHeim && !isHarheimerGast) return false
|
|
|
|
const mannschaftMatch = variants.some((variant) => {
|
|
if (isHarheimerHeim && isExactHarheimTeam(heimMannschaft, variant)) return true
|
|
if (isHarheimerGast && isExactHarheimTeam(gastMannschaft, variant)) return true
|
|
return false
|
|
})
|
|
|
|
if (!mannschaftMatch) return false
|
|
|
|
if (cmsMannschaft.startsWith('Erwachsene')) {
|
|
const isErwachsenenHeim = isHarheimerHeim &&
|
|
heimAltersklasse.includes('erwachsene') &&
|
|
!heimAltersklasse.includes('jugend')
|
|
const isErwachsenenGast = isHarheimerGast &&
|
|
gastAltersklasse.includes('erwachsene') &&
|
|
!gastAltersklasse.includes('jugend')
|
|
return isErwachsenenHeim || isErwachsenenGast
|
|
}
|
|
|
|
if (cmsMannschaft === 'Jugendmannschaft') {
|
|
const isJugendHeim = isHarheimerHeim &&
|
|
(heimAltersklasse.includes('jugend') || heimMannschaft.includes('jugend'))
|
|
const isJugendGast = isHarheimerGast &&
|
|
(gastAltersklasse.includes('jugend') || gastMannschaft.includes('jugend'))
|
|
return isJugendHeim || isJugendGast
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
const parseTerminTimestamp = (row) => {
|
|
const timestamp = Number(row.Timestamp)
|
|
if (Number.isFinite(timestamp) && timestamp > 0) return timestamp
|
|
|
|
const termin = String(row.Termin || '')
|
|
const match = termin.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2}):(\d{2}))?/)
|
|
if (!match) return 0
|
|
|
|
const [, day, month, year, hour = '0', minute = '0'] = match
|
|
return new Date(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute)).getTime() / 1000
|
|
}
|
|
|
|
const loadSpielplan = async () => {
|
|
if (!mannschaft.value) return
|
|
|
|
isSpielplanLoading.value = true
|
|
spielplanError.value = ''
|
|
|
|
try {
|
|
const response = await fetch('/api/spielplan')
|
|
const result = await response.json()
|
|
|
|
if (!result.success) {
|
|
spielplanError.value = result.message || 'Spielplan konnte nicht geladen werden.'
|
|
mannschaftSpielplan.value = []
|
|
return
|
|
}
|
|
|
|
spielplanSeason.value = result.season || ''
|
|
mannschaftSpielplan.value = result.data
|
|
.filter(row => isSpielForMannschaft(row, mannschaft.value.mannschaft))
|
|
.sort((a, b) => parseTerminTimestamp(a) - parseTerminTimestamp(b))
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden des Spielplans:', error)
|
|
spielplanError.value = 'Spielplan konnte nicht geladen werden.'
|
|
mannschaftSpielplan.value = []
|
|
} finally {
|
|
isSpielplanLoading.value = false
|
|
}
|
|
}
|
|
|
|
const getSpielerListe = (mannschaft) => {
|
|
if (!mannschaft.spieler) return []
|
|
return mannschaft.spieler.split(';').map(s => s.trim()).filter(s => s !== '')
|
|
}
|
|
|
|
const formatDate = (dateString) => {
|
|
if (!dateString) return ''
|
|
|
|
// Wenn bereits im Format DD.MM.YYYY, direkt zurückgeben
|
|
if (/^\d{2}\.\d{2}\.\d{4}$/.test(dateString)) {
|
|
return dateString
|
|
}
|
|
|
|
// Versuche, das Datum zu parsen
|
|
const date = new Date(dateString)
|
|
if (isNaN(date.getTime())) {
|
|
return dateString // Falls ungültig, Original zurückgeben
|
|
}
|
|
|
|
return date.toLocaleDateString('de-DE', {
|
|
day: '2-digit',
|
|
month: '2-digit',
|
|
year: 'numeric'
|
|
})
|
|
}
|
|
|
|
const formatResult = (row) => {
|
|
const heim = String(row?.SpieleHeim || '').trim()
|
|
const gast = String(row?.SpieleGast || '').trim()
|
|
return heim || gast ? `${heim}:${gast}` : '-'
|
|
}
|
|
|
|
const formatRunde = (rundeString) => {
|
|
if (!rundeString) return '-'
|
|
|
|
const runde = rundeString.toLowerCase()
|
|
if (runde === 'vr') return 'Vorrunde'
|
|
if (runde === 'rr') return 'Rückrunde'
|
|
if (runde === 'pokal') return 'Pokal'
|
|
return rundeString
|
|
}
|
|
|
|
const formatStaffel = (staffelString) => {
|
|
const staffel = String(staffelString || '').trim()
|
|
if (!staffel) return '-'
|
|
return staffel.replace(/^E(?=\d)/, '')
|
|
}
|
|
|
|
const getRowClass = (row) => {
|
|
const timestamp = parseTerminTimestamp(row)
|
|
if (!timestamp) return 'bg-white'
|
|
|
|
const spielDatum = new Date(timestamp * 1000)
|
|
spielDatum.setHours(0, 0, 0, 0)
|
|
|
|
const heute = new Date()
|
|
heute.setHours(0, 0, 0, 0)
|
|
|
|
const in7Tagen = new Date(heute)
|
|
in7Tagen.setDate(in7Tagen.getDate() + 7)
|
|
|
|
if (spielDatum.getTime() === heute.getTime()) return 'bg-yellow-100'
|
|
if (spielDatum > heute && spielDatum <= in7Tagen) return 'bg-blue-100'
|
|
return 'bg-white'
|
|
}
|
|
|
|
const formatSun = (row) => {
|
|
const s = row?.meetings_won
|
|
const u = row?.meetings_tie
|
|
const n = row?.meetings_lost
|
|
if (s == null && u == null && n == null) return '-'
|
|
return `${s ?? 0}/${u ?? 0}/${n ?? 0}`
|
|
}
|
|
|
|
const formatPunkte = (row) => {
|
|
if (row?.points_won == null && row?.points_lost == null) return '-'
|
|
return `${row?.points_won ?? 0}:${row?.points_lost ?? 0}`
|
|
}
|
|
|
|
const isCurrentTeamRow = (row) => {
|
|
const teamName = String(row?.team_name || '').toLowerCase()
|
|
if (!teamName.includes('harheimer tc')) return false
|
|
|
|
const variants = getTeamVariants(mannschaft.value?.mannschaft || '')
|
|
return variants.some((variant) => isExactHarheimTeam(teamName, variant))
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadMannschaften()
|
|
})
|
|
</script>
|