Add 'Vereinsmeisterschaften' link to Navigation component; update CSV header format and add new entry for 2025

This commit is contained in:
Torsten Schulz (local)
2025-10-23 16:52:08 +02:00
parent a4269e970b
commit c6ce26773a
4 changed files with 714 additions and 1 deletions

View File

@@ -230,6 +230,11 @@
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"> class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors">
Satzung Satzung
</NuxtLink> </NuxtLink>
<NuxtLink to="/cms/vereinsmeisterschaften"
@click="showCmsDropdown = false"
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors">
Vereinsmeisterschaften
</NuxtLink>
<div class="border-t border-gray-700 my-1"></div> <div class="border-t border-gray-700 my-1"></div>
<NuxtLink to="/mitgliederbereich/news" <NuxtLink to="/mitgliederbereich/news"
@click="showCmsDropdown = false" @click="showCmsDropdown = false"
@@ -465,6 +470,10 @@
class="block px-4 py-2 text-sm text-yellow-300 hover:text-white hover:bg-primary-700/50 rounded-lg transition-colors"> class="block px-4 py-2 text-sm text-yellow-300 hover:text-white hover:bg-primary-700/50 rounded-lg transition-colors">
Satzung Satzung
</NuxtLink> </NuxtLink>
<NuxtLink to="/cms/vereinsmeisterschaften" @click="isMobileMenuOpen = false"
class="block px-4 py-2 text-sm text-yellow-300 hover:text-white hover:bg-primary-700/50 rounded-lg transition-colors">
Vereinsmeisterschaften
</NuxtLink>
<NuxtLink to="/cms/einstellungen" @click="isMobileMenuOpen = false" <NuxtLink to="/cms/einstellungen" @click="isMobileMenuOpen = false"
class="block px-4 py-2 text-sm text-yellow-300 hover:text-white hover:bg-primary-700/50 rounded-lg transition-colors"> class="block px-4 py-2 text-sm text-yellow-300 hover:text-white hover:bg-primary-700/50 rounded-lg transition-colors">
Einstellungen Einstellungen

View File

@@ -0,0 +1,652 @@
<template>
<div class="min-h-full bg-gray-50">
<!-- Fixed Header below navigation -->
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
<div class="flex items-center justify-between">
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">Vereinsmeisterschaften bearbeiten</h1>
<div class="space-x-3">
<button @click="addNewResult" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-green-600 text-white hover:bg-green-700 text-sm sm:text-base">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Neues Ergebnis
</button>
<button @click="save" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base">Speichern</button>
</div>
</div>
</div>
</div>
<!-- Content with top padding -->
<div class="pt-20 pb-16">
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Filter -->
<div class="mb-8 flex flex-wrap gap-4">
<button
v-for="jahr in verfuegbareJahre"
:key="jahr"
@click="selectedYear = jahr"
:class="[
'px-4 py-2 rounded-lg font-medium transition-colors',
selectedYear === jahr
? 'bg-primary-600 text-white'
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
]"
>
{{ jahr }}
</button>
<button
@click="selectedYear = 'alle'"
:class="[
'px-4 py-2 rounded-lg font-medium transition-colors',
selectedYear === 'alle'
? 'bg-primary-600 text-white'
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
]"
>
Alle Jahre
</button>
</div>
<!-- Ergebnisse -->
<div v-if="filteredResults.length > 0" class="space-y-8">
<div
v-for="(jahrData, jahr) in sortedGroupedResults"
:key="jahr"
class="bg-white rounded-xl shadow-lg p-6"
>
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-display font-bold text-gray-900">{{ jahr }}</h2>
<div class="flex space-x-2">
<button
@click="addResultForYear(jahr)"
class="px-3 py-1 text-sm bg-green-100 hover:bg-green-200 text-green-700 rounded-lg transition-colors"
>
Ergebnis hinzufügen
</button>
<button
@click="deleteYear(jahr)"
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
>
Jahr löschen
</button>
</div>
</div>
<!-- Besondere Bemerkungen -->
<div v-if="jahrData.bemerkungen" class="mb-6 p-4 bg-yellow-50 border-l-4 border-yellow-400 rounded-r-lg">
<div class="flex items-center justify-between">
<p class="text-gray-700 font-medium">{{ jahrData.bemerkungen }}</p>
<button
@click="editBemerkung(jahr)"
class="px-2 py-1 text-xs bg-yellow-100 hover:bg-yellow-200 text-yellow-700 rounded transition-colors"
>
Bearbeiten
</button>
</div>
</div>
<!-- Kategorien -->
<div v-if="Object.keys(jahrData.kategorien).length > 0" class="space-y-6">
<div
v-for="(kategorieResults, kategorie) in jahrData.kategorien"
:key="kategorie"
class="border border-gray-200 rounded-lg p-4"
>
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900">{{ kategorie }}</h3>
<div class="flex space-x-2">
<button
@click="addResultForKategorie(jahr, kategorie)"
class="px-2 py-1 text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 rounded transition-colors"
>
Ergebnis hinzufügen
</button>
<button
@click="deleteKategorie(jahr, kategorie)"
class="px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors"
>
Kategorie löschen
</button>
</div>
</div>
<div class="space-y-3">
<div
v-for="(result, index) in kategorieResults"
:key="index"
class="flex items-center justify-between p-3 bg-gray-50 rounded-lg"
>
<div class="flex items-center space-x-4">
<span class="w-8 h-8 bg-primary-600 text-white rounded-full flex items-center justify-center text-sm font-bold">
{{ result.platz }}
</span>
<div>
<span class="font-medium text-gray-900">{{ result.spieler1 }}</span>
<span v-if="result.spieler2" class="text-gray-600"> & {{ result.spieler2 }}</span>
</div>
</div>
<div class="flex space-x-2">
<button
@click="editResult(result, jahr, kategorie, index)"
class="px-2 py-1 text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 rounded transition-colors"
>
Bearbeiten
</button>
<button
@click="deleteResult(jahr, kategorie, index)"
class="px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors"
>
Löschen
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="text-center py-12 bg-white rounded-xl shadow-lg">
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"></path>
</svg>
<p class="text-gray-600">Keine Ergebnisse vorhanden.</p>
<button
@click="addNewResult"
class="mt-4 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
>
Erstes Ergebnis hinzufügen
</button>
</div>
</div>
</div>
<!-- Modal für Ergebnis bearbeiten/hinzufügen -->
<div
v-if="showModal"
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
@click.self="closeModal"
>
<div class="bg-white rounded-lg max-w-md w-full p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">
{{ editingResult ? 'Ergebnis bearbeiten' : 'Neues Ergebnis hinzufügen' }}
</h3>
<form @submit.prevent="saveResult" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Jahr</label>
<input
v-model="formData.jahr"
type="text"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Kategorie</label>
<select
v-model="formData.kategorie"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
>
<option value="">Kategorie wählen</option>
<option value="Einzel">Einzel</option>
<option value="Doppel">Doppel</option>
<option value="Mixed">Mixed</option>
<option value="Jugend">Jugend</option>
<option value="Senioren">Senioren</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Platz</label>
<select
v-model="formData.platz"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
>
<option value="">Platz wählen</option>
<option value="1">1. Platz</option>
<option value="2">2. Platz</option>
<option value="3">3. Platz</option>
<option value="4">4. Platz</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Spieler 1</label>
<input
v-model="formData.spieler1"
type="text"
required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
/>
</div>
<div v-if="formData.kategorie === 'Doppel' || formData.kategorie === 'Mixed'">
<label class="block text-sm font-medium text-gray-700 mb-2">Spieler 2</label>
<input
v-model="formData.spieler2"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung (optional)</label>
<textarea
v-model="formData.bemerkung"
rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
></textarea>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button
type="button"
@click="closeModal"
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
>
Abbrechen
</button>
<button
type="submit"
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
>
{{ editingResult ? 'Aktualisieren' : 'Hinzufügen' }}
</button>
</div>
</form>
</div>
</div>
<!-- Modal für Bemerkung bearbeiten -->
<div
v-if="showBemerkungModal"
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
@click.self="closeBemerkungModal"
>
<div class="bg-white rounded-lg max-w-md w-full p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">Bemerkung bearbeiten</h3>
<form @submit.prevent="saveBemerkung" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung</label>
<textarea
v-model="bemerkungText"
rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
></textarea>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button
type="button"
@click="closeBemerkungModal"
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
>
Abbrechen
</button>
<button
type="submit"
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
>
Speichern
</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
definePageMeta({
middleware: 'auth',
})
useHead({ title: 'CMS: Vereinsmeisterschaften' })
const results = ref([])
const selectedYear = ref('alle')
const showModal = ref(false)
const showBemerkungModal = ref(false)
const editingResult = ref(null)
const editingYear = ref(null)
const editingKategorie = ref(null)
const editingIndex = ref(null)
const bemerkungText = ref('')
const bemerkungYear = ref('')
const formData = ref({
jahr: '',
kategorie: '',
platz: '',
spieler1: '',
spieler2: '',
bemerkung: ''
})
const loadResults = async () => {
try {
const response = await fetch('/data/vereinsmeisterschaften.csv')
if (!response.ok) return
const csv = await response.text()
const lines = csv.split('\n').filter(line => line.trim() !== '')
if (lines.length < 2) return
results.value = lines.slice(1).map(line => {
// 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 < 6) return null
return {
jahr: values[0].trim(),
kategorie: values[1].trim(),
platz: values[2].trim(),
spieler1: values[3].trim(),
spieler2: values[4].trim(),
bemerkung: values[5].trim()
}
}).filter(result => result !== null)
} catch (error) {
console.error('Fehler beim Laden der Vereinsmeisterschaften:', error)
}
}
const verfuegbareJahre = computed(() => {
const jahre = [...new Set(results.value.map(r => r.jahr).filter(j => j !== ''))]
return jahre.sort((a, b) => b - a) // Neueste zuerst
})
const filteredResults = computed(() => {
if (selectedYear.value === 'alle') {
return results.value
}
return results.value.filter(r => r.jahr === selectedYear.value)
})
const groupedResults = computed(() => {
const grouped = {}
filteredResults.value.forEach(result => {
if (!grouped[result.jahr]) {
grouped[result.jahr] = {
kategorien: {},
bemerkungen: null
}
}
// Besondere Bemerkungen (z.B. coronabedingter Ausfall)
if (result.bemerkung && result.bemerkung !== '') {
grouped[result.jahr].bemerkungen = result.bemerkung
return
}
// Normale Ergebnisse
if (result.kategorie && result.kategorie !== '') {
if (!grouped[result.jahr].kategorien[result.kategorie]) {
grouped[result.jahr].kategorien[result.kategorie] = []
}
grouped[result.jahr].kategorien[result.kategorie].push(result)
}
})
return grouped
})
const sortedGroupedResults = computed(() => {
const sorted = {}
const jahre = Object.keys(groupedResults.value).sort((a, b) => b - a) // Neueste zuerst
jahre.forEach(jahr => {
sorted[jahr] = groupedResults.value[jahr]
})
return sorted
})
const addNewResult = () => {
editingResult.value = null
editingYear.value = null
editingKategorie.value = null
editingIndex.value = null
formData.value = {
jahr: '',
kategorie: '',
platz: '',
spieler1: '',
spieler2: '',
bemerkung: ''
}
showModal.value = true
}
const addResultForYear = (jahr) => {
editingResult.value = null
editingYear.value = jahr
editingKategorie.value = null
editingIndex.value = null
formData.value = {
jahr: jahr,
kategorie: '',
platz: '',
spieler1: '',
spieler2: '',
bemerkung: ''
}
showModal.value = true
}
const addResultForKategorie = (jahr, kategorie) => {
editingResult.value = null
editingYear.value = jahr
editingKategorie.value = kategorie
editingIndex.value = null
formData.value = {
jahr: jahr,
kategorie: kategorie,
platz: '',
spieler1: '',
spieler2: '',
bemerkung: ''
}
showModal.value = true
}
const editResult = (result, jahr, kategorie, index) => {
editingResult.value = result
editingYear.value = jahr
editingKategorie.value = kategorie
editingIndex.value = index
formData.value = {
jahr: result.jahr,
kategorie: result.kategorie,
platz: result.platz,
spieler1: result.spieler1,
spieler2: result.spieler2,
bemerkung: result.bemerkung
}
showModal.value = true
}
const editBemerkung = (jahr) => {
bemerkungYear.value = jahr
bemerkungText.value = groupedResults.value[jahr]?.bemerkungen || ''
showBemerkungModal.value = true
}
const saveResult = async () => {
if (editingResult.value) {
// Ergebnis aktualisieren
const resultIndex = results.value.findIndex(r =>
r.jahr === editingResult.value.jahr &&
r.kategorie === editingResult.value.kategorie &&
r.platz === editingResult.value.platz &&
r.spieler1 === editingResult.value.spieler1 &&
r.spieler2 === editingResult.value.spieler2
)
if (resultIndex !== -1) {
results.value[resultIndex] = { ...formData.value }
}
} else {
// Neues Ergebnis hinzufügen
results.value.push({ ...formData.value })
}
closeModal()
}
const saveBemerkung = async () => {
// Bemerkung als separates Ergebnis speichern
const existingBemerkungIndex = results.value.findIndex(r =>
r.jahr === bemerkungYear.value &&
r.kategorie === '' &&
r.platz === '' &&
r.spieler1 === '' &&
r.spieler2 === '' &&
r.bemerkung !== ''
)
if (existingBemerkungIndex !== -1) {
results.value[existingBemerkungIndex].bemerkung = bemerkungText.value
} else {
results.value.push({
jahr: bemerkungYear.value,
kategorie: '',
platz: '',
spieler1: '',
spieler2: '',
bemerkung: bemerkungText.value
})
}
closeBemerkungModal()
}
const deleteResult = (jahr, kategorie, index) => {
if (confirm('Möchten Sie dieses Ergebnis wirklich löschen?')) {
const resultToDelete = groupedResults.value[jahr].kategorien[kategorie][index]
const resultIndex = results.value.findIndex(r =>
r.jahr === resultToDelete.jahr &&
r.kategorie === resultToDelete.kategorie &&
r.platz === resultToDelete.platz &&
r.spieler1 === resultToDelete.spieler1 &&
r.spieler2 === resultToDelete.spieler2
)
if (resultIndex !== -1) {
results.value.splice(resultIndex, 1)
}
}
}
const deleteKategorie = (jahr, kategorie) => {
if (confirm(`Möchten Sie die Kategorie "${kategorie}" für ${jahr} wirklich löschen?`)) {
const kategorieResults = groupedResults.value[jahr].kategorien[kategorie]
kategorieResults.forEach(result => {
const resultIndex = results.value.findIndex(r =>
r.jahr === result.jahr &&
r.kategorie === result.kategorie &&
r.platz === result.platz &&
r.spieler1 === result.spieler1 &&
r.spieler2 === result.spieler2
)
if (resultIndex !== -1) {
results.value.splice(resultIndex, 1)
}
})
}
}
const deleteYear = (jahr) => {
if (confirm(`Möchten Sie alle Ergebnisse für ${jahr} wirklich löschen?`)) {
results.value = results.value.filter(r => r.jahr !== jahr)
}
}
const closeModal = () => {
showModal.value = false
editingResult.value = null
editingYear.value = null
editingKategorie.value = null
editingIndex.value = null
}
const closeBemerkungModal = () => {
showBemerkungModal.value = false
bemerkungText.value = ''
bemerkungYear.value = ''
}
const save = async () => {
try {
// CSV generieren
const csvHeader = 'Jahr,Kategorie,Platz,Spieler1,Spieler2,Bemerkung'
const csvRows = results.value.map(result => {
return [
result.jahr,
result.kategorie,
result.platz,
result.spieler1,
result.spieler2,
result.bemerkung
].map(field => `"${field}"`).join(',')
})
const csvContent = [csvHeader, ...csvRows].join('\n')
// CSV speichern
const response = await fetch('/api/cms/save-csv', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
filename: 'vereinsmeisterschaften.csv',
content: csvContent
})
})
if (response.ok) {
alert('Vereinsmeisterschaften erfolgreich gespeichert!')
} else {
alert('Fehler beim Speichern der Vereinsmeisterschaften!')
}
} catch (error) {
console.error('Fehler beim Speichern:', error)
alert('Fehler beim Speichern der Vereinsmeisterschaften!')
}
}
onMounted(() => {
loadResults()
})
</script>

View File

@@ -1,4 +1,4 @@
"jahr","kategorie","platz","spieler1","spieler2","bemerkung" Jahr,Kategorie,Platz,Spieler1,Spieler2,Bemerkung
"2024","Einzel","1","Michael Koch","","" "2024","Einzel","1","Michael Koch","",""
"2024","Einzel","2","Olaf Nüßlein","","" "2024","Einzel","2","Olaf Nüßlein","",""
"2024","Einzel","3","Bernd Meyer","","" "2024","Einzel","3","Bernd Meyer","",""
@@ -46,3 +46,4 @@
"2016","Doppel","1","Jürgen Kratz","Matthias Schmidt","" "2016","Doppel","1","Jürgen Kratz","Matthias Schmidt",""
"2016","Doppel","2","André Gilzinger","Bernd Meyer","" "2016","Doppel","2","André Gilzinger","Bernd Meyer",""
"2016","Doppel","3","Sven Baublies","Dagmar Bereksasi","" "2016","Doppel","3","Sven Baublies","Dagmar Bereksasi",""
"2025","Doppel","1","a","b",""
1 jahr Jahr kategorie Kategorie platz Platz spieler1 Spieler1 spieler2 Spieler2 bemerkung Bemerkung
2 2024 Einzel 1 Michael Koch
3 2024 Einzel 2 Olaf Nüßlein
4 2024 Einzel 3 Bernd Meyer
46 2016 Doppel 1 Jürgen Kratz Matthias Schmidt
47 2016 Doppel 2 André Gilzinger Bernd Meyer
48 2016 Doppel 3 Sven Baublies Dagmar Bereksasi
49 2025 Doppel 1 a b

View File

@@ -0,0 +1,51 @@
import fs from 'fs/promises'
import path from 'path'
export default defineEventHandler(async (event) => {
try {
const { filename, content } = await readBody(event)
if (!filename || !content) {
throw createError({
statusCode: 400,
statusMessage: 'Filename und Content sind erforderlich'
})
}
// Sicherheitsprüfung: Nur bestimmte Dateien erlauben
const allowedFiles = [
'vereinsmeisterschaften.csv',
'mannschaften.csv',
'termine.csv'
]
if (!allowedFiles.includes(filename)) {
throw createError({
statusCode: 403,
statusMessage: 'Datei nicht erlaubt'
})
}
// Pfad zur Datenverzeichnis
const dataDir = path.join(process.cwd(), 'public', 'data')
const filePath = path.join(dataDir, filename)
// Sicherstellen, dass das Verzeichnis existiert
await fs.mkdir(dataDir, { recursive: true })
// Datei schreiben
await fs.writeFile(filePath, content, 'utf8')
return {
success: true,
message: 'Datei erfolgreich gespeichert'
}
} catch (error) {
console.error('Fehler beim Speichern der CSV-Datei:', error)
throw createError({
statusCode: 500,
statusMessage: 'Fehler beim Speichern der Datei'
})
}
})