Add script for importing match schedule and logging
Some checks failed
Code Analysis and Production Deploy / analyze (push) Has been skipped
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m2s
Code Analysis and Production Deploy / analyze (pull_request) Failing after 33s
Code Analysis and Production Deploy / deploy-production (pull_request) Has been skipped
Code Analysis and Production Deploy / deploy-test (pull_request) Has been skipped
Require Package Version Change / check (pull_request) Failing after 10s
Some checks failed
Code Analysis and Production Deploy / analyze (push) Has been skipped
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m2s
Code Analysis and Production Deploy / analyze (pull_request) Failing after 33s
Code Analysis and Production Deploy / deploy-production (pull_request) Has been skipped
Code Analysis and Production Deploy / deploy-test (pull_request) Has been skipped
Require Package Version Change / check (pull_request) Failing after 10s
- Created `import-spielplan.js` to fetch and parse the match schedule from the specified URL, saving the output as JSON. - Added `run-spielplan-import.sh` to automate the execution of the import script and log output. - Introduced `spielplan.html` file to store the downloaded HTML content for further processing.
This commit is contained in:
@@ -73,6 +73,105 @@
|
||||
</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">
|
||||
<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
|
||||
v-if="isSpielplanLoading"
|
||||
class="p-6 text-sm text-gray-600"
|
||||
>
|
||||
Spielplan wird geladen...
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="spielplanError"
|
||||
class="p-6 text-sm text-red-600"
|
||||
>
|
||||
{{ spielplanError }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="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
|
||||
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>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||
<h2 class="text-2xl font-semibold text-gray-900 mb-6">
|
||||
@@ -134,11 +233,20 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
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 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 () => {
|
||||
@@ -209,12 +317,118 @@ const loadMannschaften = async () => {
|
||||
useHead({
|
||||
title: `${mannschaft.value.mannschaft} - Harheimer TC`,
|
||||
})
|
||||
await loadSpielplan()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Mannschaften:', error)
|
||||
}
|
||||
}
|
||||
|
||||
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 !== '')
|
||||
@@ -241,6 +455,46 @@ const formatDate = (dateString) => {
|
||||
})
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadMannschaften()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user