Refactor PDF upload and CSV parsing logic in 'spielplaene' and 'mannschaften' components; implement automatic delimiter detection for CSV files and enhance hall information extraction for improved data handling. Update UI to remove PDF upload section and streamline CSV upload process.
This commit is contained in:
@@ -22,71 +22,6 @@
|
||||
<div class="pt-20 pb-16">
|
||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
|
||||
<!-- PDF Upload Section -->
|
||||
<div class="mb-8 bg-white rounded-xl shadow-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-900 mb-4">Spielplan PDF-Dateien</h2>
|
||||
<p class="text-sm text-gray-600 mb-6">Laden Sie die PDF-Dateien für die verschiedenen Spielpläne hoch:</p>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-3">
|
||||
<!-- Gesamt PDF -->
|
||||
<div class="border border-gray-200 rounded-lg p-4">
|
||||
<h3 class="font-medium text-gray-900 mb-2">Gesamt</h3>
|
||||
<p class="text-sm text-gray-600 mb-3">Alle Mannschaften</p>
|
||||
<input
|
||||
ref="gesamtPdfInput"
|
||||
type="file"
|
||||
accept=".pdf"
|
||||
@change="handlePdfUpload('gesamt', $event)"
|
||||
class="hidden"
|
||||
/>
|
||||
<button @click="triggerPdfInput('gesamt')" class="w-full px-3 py-2 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors">
|
||||
PDF hochladen
|
||||
</button>
|
||||
<div v-if="uploadedPdfs.gesamt" class="mt-2 text-xs text-green-600">
|
||||
✓ {{ uploadedPdfs.gesamt }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Erwachsene PDF -->
|
||||
<div class="border border-gray-200 rounded-lg p-4">
|
||||
<h3 class="font-medium text-gray-900 mb-2">Erwachsene</h3>
|
||||
<p class="text-sm text-gray-600 mb-3">Erwachsenen-Mannschaften</p>
|
||||
<input
|
||||
ref="erwachsenePdfInput"
|
||||
type="file"
|
||||
accept=".pdf"
|
||||
@change="handlePdfUpload('erwachsene', $event)"
|
||||
class="hidden"
|
||||
/>
|
||||
<button @click="triggerPdfInput('erwachsene')" class="w-full px-3 py-2 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors">
|
||||
PDF hochladen
|
||||
</button>
|
||||
<div v-if="uploadedPdfs.erwachsene" class="mt-2 text-xs text-green-600">
|
||||
✓ {{ uploadedPdfs.erwachsene }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nachwuchs PDF -->
|
||||
<div class="border border-gray-200 rounded-lg p-4">
|
||||
<h3 class="font-medium text-gray-900 mb-2">Nachwuchs</h3>
|
||||
<p class="text-sm text-gray-600 mb-3">Nachwuchs-Mannschaften</p>
|
||||
<input
|
||||
ref="nachwuchsPdfInput"
|
||||
type="file"
|
||||
accept=".pdf"
|
||||
@change="handlePdfUpload('nachwuchs', $event)"
|
||||
class="hidden"
|
||||
/>
|
||||
<button @click="triggerPdfInput('nachwuchs')" class="w-full px-3 py-2 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors">
|
||||
PDF hochladen
|
||||
</button>
|
||||
<div v-if="uploadedPdfs.nachwuchs" class="mt-2 text-xs text-green-600">
|
||||
✓ {{ uploadedPdfs.nachwuchs }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CSV Upload Section -->
|
||||
<div class="mb-8 bg-white rounded-xl shadow-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-900 mb-4">Vereins-Spielplan (CSV)</h2>
|
||||
@@ -171,6 +106,9 @@
|
||||
<button @click="deselectAllColumns" class="px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors">
|
||||
Alle abwählen
|
||||
</button>
|
||||
<button @click="suggestHalleColumns" class="px-4 py-2 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors">
|
||||
Halle-Spalten vorschlagen
|
||||
</button>
|
||||
<button @click="confirmColumnSelection"
|
||||
:disabled="selectedColumnsCount === 0"
|
||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400">
|
||||
@@ -318,9 +256,6 @@ useHead({ title: 'CMS: Spielpläne' })
|
||||
|
||||
const fileInput = ref(null)
|
||||
const modalFileInput = ref(null)
|
||||
const gesamtPdfInput = ref(null)
|
||||
const erwachsenePdfInput = ref(null)
|
||||
const nachwuchsPdfInput = ref(null)
|
||||
const showUploadModal = ref(false)
|
||||
const isProcessing = ref(false)
|
||||
const processingMessage = ref('')
|
||||
@@ -334,57 +269,10 @@ const selectedColumns = ref([])
|
||||
const columnsSelected = ref(false)
|
||||
const filteredCsvData = ref([])
|
||||
const filteredCsvHeaders = ref([])
|
||||
const uploadedPdfs = ref({
|
||||
gesamt: null,
|
||||
erwachsene: null,
|
||||
nachwuchs: null
|
||||
})
|
||||
|
||||
const triggerFileInput = () => {
|
||||
fileInput.value?.click()
|
||||
}
|
||||
|
||||
const triggerPdfInput = (type) => {
|
||||
if (type === 'gesamt') {
|
||||
gesamtPdfInput.value?.click()
|
||||
} else if (type === 'erwachsene') {
|
||||
erwachsenePdfInput.value?.click()
|
||||
} else if (type === 'nachwuchs') {
|
||||
nachwuchsPdfInput.value?.click()
|
||||
}
|
||||
}
|
||||
|
||||
const handlePdfUpload = async (type, event) => {
|
||||
const file = event.target.files[0]
|
||||
if (!file) return
|
||||
|
||||
if (file.type !== 'application/pdf') {
|
||||
alert('Bitte wählen Sie eine PDF-Datei aus.')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('pdf', file)
|
||||
formData.append('type', type)
|
||||
|
||||
const response = await fetch('/api/cms/upload-spielplan-pdf', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
uploadedPdfs.value[type] = file.name
|
||||
alert(`PDF für ${type} erfolgreich hochgeladen!`)
|
||||
} else {
|
||||
alert('Fehler beim Hochladen der PDF-Datei!')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim PDF-Upload:', error)
|
||||
alert('Fehler beim Hochladen der PDF-Datei!')
|
||||
}
|
||||
}
|
||||
|
||||
const handleFileSelect = (event) => {
|
||||
const file = event.target.files[0]
|
||||
if (file) {
|
||||
@@ -417,9 +305,14 @@ const processFile = async (file) => {
|
||||
throw new Error('CSV-Datei muss mindestens eine Kopfzeile und eine Datenzeile enthalten')
|
||||
}
|
||||
|
||||
// CSV-Parser: Semikolon-getrennt, ohne Anführungszeichen
|
||||
// CSV-Parser: Automatische Erkennung von Trennzeichen (Tab oder Semikolon)
|
||||
const parseCSVLine = (line) => {
|
||||
return line.split(';').map(value => value.trim())
|
||||
// Prüfe ob Tab oder Semikolon häufiger vorkommt
|
||||
const tabCount = (line.match(/\t/g) || []).length
|
||||
const semicolonCount = (line.match(/;/g) || []).length
|
||||
|
||||
const delimiter = tabCount > semicolonCount ? '\t' : ';'
|
||||
return line.split(delimiter).map(value => value.trim())
|
||||
}
|
||||
|
||||
// Header-Zeile parsen
|
||||
@@ -432,6 +325,16 @@ const processFile = async (file) => {
|
||||
selectedColumns.value = new Array(csvHeaders.value.length).fill(true)
|
||||
columnsSelected.value = false
|
||||
|
||||
// Debug: Zeige verfügbare Spalten
|
||||
console.log('Verfügbare Spalten:', csvHeaders.value)
|
||||
const halleSpalten = csvHeaders.value.filter(header =>
|
||||
header.toLowerCase().includes('halle') ||
|
||||
header.toLowerCase().includes('strasse') ||
|
||||
header.toLowerCase().includes('plz') ||
|
||||
header.toLowerCase().includes('ort')
|
||||
)
|
||||
console.log('Halle-Spalten gefunden:', halleSpalten)
|
||||
|
||||
// Datei-Info speichern
|
||||
currentFile.value = {
|
||||
name: file.name,
|
||||
@@ -501,6 +404,19 @@ const confirmColumnSelection = () => {
|
||||
columnsSelected.value = true
|
||||
}
|
||||
|
||||
const suggestHalleColumns = () => {
|
||||
// Automatisch Halle-Spalten vorschlagen
|
||||
csvHeaders.value.forEach((header, index) => {
|
||||
const headerLower = header.toLowerCase()
|
||||
if (headerLower.includes('halle') ||
|
||||
headerLower.includes('strasse') ||
|
||||
headerLower.includes('plz') ||
|
||||
headerLower.includes('ort')) {
|
||||
selectedColumns.value[index] = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const clearData = () => {
|
||||
if (confirm('Möchten Sie alle Daten wirklich löschen?')) {
|
||||
removeFile()
|
||||
|
||||
Reference in New Issue
Block a user