Implement CSV fetching utility across components for improved data handling
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 46s

This commit introduces a new utility function, fetchCsvText, to streamline the fetching of CSV data across multiple components. The function includes a cache-busting mechanism and retry logic to enhance reliability when retrieving data from the server. This change improves error handling and ensures consistent data retrieval in the Mannschaften overview, detail, and schedule pages, contributing to a more robust application.
This commit is contained in:
Torsten Schulz (local)
2026-01-18 23:40:59 +01:00
parent fa12bae426
commit 8043916129
4 changed files with 70 additions and 17 deletions

View File

@@ -107,15 +107,25 @@ import { Users } from 'lucide-vue-next'
const mannschaften = ref([]) const mannschaften = ref([])
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) throw new Error(`HTTP error! status: ${res.status}`)
return await res.text()
}
try {
return await attempt()
} catch (_e) {
await new Promise(resolve => setTimeout(resolve, 150))
return await attempt()
}
}
const loadMannschaften = async () => { const loadMannschaften = async () => {
try { try {
const response = await fetch('/data/mannschaften.csv') const csv = await fetchCsvText('/data/mannschaften.csv')
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const csv = await response.text()
// Vereinfachter CSV-Parser // Vereinfachter CSV-Parser
const lines = csv.split('\n').filter(line => line.trim() !== '') const lines = csv.split('\n').filter(line => line.trim() !== '')

View File

@@ -923,10 +923,22 @@ const toggleMobileSubmenu = (menu) => {
const loadMannschaften = async () => { const loadMannschaften = async () => {
try { try {
const response = await fetch('/data/mannschaften.csv') const attempt = async () => {
if (!response.ok) return const url = `/data/mannschaften.csv?_t=${Date.now()}`
const response = await fetch(url, { cache: 'no-store' })
if (!response.ok) return null
return await response.text()
}
const csv = await response.text() let csv = null
try {
csv = await attempt()
} catch (_e) {
// 1 Retry: hilft bei kurzen Restarts/Proxy-Resets (Firefox: NS_ERROR_NET_PARTIAL_TRANSFER)
await new Promise(resolve => setTimeout(resolve, 150))
csv = await attempt()
}
if (!csv) return
const lines = csv.split('\n').filter(line => line.trim() !== '') const lines = csv.split('\n').filter(line => line.trim() !== '')
if (lines.length < 2) return if (lines.length < 2) return

View File

@@ -140,12 +140,26 @@ import { Users } from 'lucide-vue-next'
const route = useRoute() const route = useRoute()
const mannschaft = ref(null) const mannschaft = ref(null)
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 () => { const loadMannschaften = async () => {
try { try {
const response = await fetch('/data/mannschaften.csv') const csv = await fetchCsvText('/data/mannschaften.csv')
if (!response.ok) return if (!csv) return
const csv = await response.text()
const lines = csv.split('\n').filter(line => line.trim() !== '') const lines = csv.split('\n').filter(line => line.trim() !== '')
if (lines.length < 2) return if (lines.length < 2) return

View File

@@ -299,6 +299,23 @@ const selectedWettbewerb = ref('punktrunde')
const filteredData = ref([]) const filteredData = ref([])
const mannschaften = ref([]) const mannschaften = ref([])
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) throw new Error(`HTTP error! status: ${res.status}`)
return await res.text()
}
try {
return await attempt()
} catch (_e) {
// 1 Retry: hilft bei kurzen Restarts/Proxy-Resets (Firefox: NS_ERROR_NET_PARTIAL_TRANSFER)
await new Promise(resolve => setTimeout(resolve, 150))
return await attempt()
}
}
const loadData = async () => { const loadData = async () => {
isLoading.value = true isLoading.value = true
error.value = null error.value = null
@@ -307,7 +324,7 @@ const loadData = async () => {
// Lade Spielplandaten und Mannschaften parallel // Lade Spielplandaten und Mannschaften parallel
const [spielplanResponse, mannschaftenResponse] = await Promise.all([ const [spielplanResponse, mannschaftenResponse] = await Promise.all([
fetch('/api/spielplan'), fetch('/api/spielplan'),
fetch('/data/mannschaften.csv') fetchCsvText('/data/mannschaften.csv')
]) ])
// Spielplandaten verarbeiten // Spielplandaten verarbeiten
@@ -352,8 +369,8 @@ const loadData = async () => {
} }
// Mannschaften aus CMS laden (manuell eingegebene Mannschaften) // Mannschaften aus CMS laden (manuell eingegebene Mannschaften)
if (mannschaftenResponse.ok) { if (mannschaftenResponse) {
const csvText = await mannschaftenResponse.text() const csvText = mannschaftenResponse
const lines = csvText.split('\n').filter(line => line.trim() !== '') const lines = csvText.split('\n').filter(line => line.trim() !== '')
if (lines.length > 1) { if (lines.length > 1) {