dev #46

Merged
admin merged 13 commits from dev into main 2026-07-17 14:00:13 +02:00
2 changed files with 41 additions and 19 deletions
Showing only changes of commit 1beb5c2eee - Show all commits

View File

@@ -204,20 +204,27 @@
</div> </div>
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-2">Spielplan-Team-IDs</label> <label class="block text-sm font-medium text-gray-700 mb-2">Spielplan-Team-IDs</label>
<select <div class="max-h-48 overflow-y-auto rounded-lg border border-gray-300 divide-y divide-gray-100">
:value="selectedSpielplanTeamIds" <label
multiple v-for="team in spielplanTeams"
size="4" :key="team.id"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500" class="flex items-start gap-3 px-4 py-3 cursor-pointer hover:bg-gray-50"
:disabled="isSaving" >
@change="updateSpielplanTeamIds" <input
> :checked="selectedSpielplanTeamIds.includes(team.id)"
<option v-for="team in spielplanTeams" :key="team.id" :value="team.id"> type="checkbox"
{{ team.label }} class="mt-0.5 h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-500"
</option> :disabled="isSaving"
</select> @change="toggleSpielplanTeamId(team.id, $event.target.checked)"
>
<span class="text-sm text-gray-800">{{ team.label }}</span>
</label>
<p v-if="!spielplanTeams.length" class="px-4 py-3 text-sm text-gray-500">
Noch keine importierten Spielplan-Teams verfügbar.
</p>
</div>
<p class="mt-1 text-xs text-gray-500"> <p class="mt-1 text-xs text-gray-500">
Nach dem myTischtennis-Import alle passenden Einträge auswählen (z. B. Liga und Pokal). Mit Strg bzw. Cmd lassen sich mehrere Einträge markieren. Alle passenden Einträge auswählen (z. B. Liga und Pokal). Die Auswahl wird beim Speichern beibehalten.
</p> </p>
</div> </div>
<div> <div>
@@ -447,8 +454,11 @@ function parseSpielerString(s) { if (!s) return []; return String(s).split(';').
function serializeSpielerList(list) { return (list || []).map(s => (s?.name || '').trim()).filter(Boolean).join('; ') } function serializeSpielerList(list) { return (list || []).map(s => (s?.name || '').trim()).filter(Boolean).join('; ') }
function serializeSpielerNames(names) { return (names || []).map(s => String(s || '').trim()).filter(Boolean).join('; ') } function serializeSpielerNames(names) { return (names || []).map(s => String(s || '').trim()).filter(Boolean).join('; ') }
const selectedSpielplanTeamIds = computed(() => String(formData.value.spielplan_mannschaft_id || '').split(',').map(id => id.trim()).filter(Boolean)) const selectedSpielplanTeamIds = computed(() => String(formData.value.spielplan_mannschaft_id || '').split(',').map(id => id.trim()).filter(Boolean))
const updateSpielplanTeamIds = (event) => { const toggleSpielplanTeamId = (id, checked) => {
formData.value.spielplan_mannschaft_id = Array.from(event.target.selectedOptions, option => option.value).join(',') const ids = new Set(selectedSpielplanTeamIds.value)
if (checked) ids.add(id)
else ids.delete(id)
formData.value.spielplan_mannschaft_id = [...ids].join(',')
} }
async function fetchCsvText(url) { async function fetchCsvText(url) {

View File

@@ -54,8 +54,9 @@ function romanToNumber(value) {
return result || null return result || null
} }
function getCmsTeamCriteria(name) { function getCmsTeamCriteria(name, league) {
const youth = String(name || '').trim().match(/^jugend\s+j(\d{1,2})(?:\s+([ivx]+|\d+))?\b/i) const teamName = String(name || '').trim()
const youth = teamName.match(/^jugend\s+j(\d{1,2})(?:\s+([ivx]+|\d+))?\b/i)
if (youth) { if (youth) {
const rawNumber = youth[2] const rawNumber = youth[2]
return { return {
@@ -64,7 +65,18 @@ function getCmsTeamCriteria(name) {
} }
} }
const adult = String(name || '').trim().match(/^erwachsene\s+(\d+)\b/i) // In bestehenden CMS-Daten steht die Altersklasse häufig nur in der Liga,
// z. B. Mannschaft "Jugend I" mit Liga "Jugend 13 (J13)".
const ageMatch = `${teamName} ${String(league || '')}`.match(/\b(?:jugend\s*|j\s*\(?)(\d{1,2})\b/i)
if (ageMatch) {
const ordinal = teamName.match(/^jugend\s+([ivx]+|\d+)\b/i)?.[1]
return {
ageClass: `Jugend ${ageMatch[1]}`,
teamNumber: ordinal ? (Number(ordinal) || romanToNumber(ordinal)) : null
}
}
const adult = teamName.match(/^erwachsene\s+(\d+)\b/i)
if (adult) return { ageClass: 'Erwachsene', teamNumber: Number(adult[1]) } if (adult) return { ageClass: 'Erwachsene', teamNumber: Number(adult[1]) }
return null return null
} }
@@ -114,7 +126,7 @@ export async function synchronizeMannschaftenSpielplanIds(seasonSlug) {
let updatedTeams = 0 let updatedTeams = 0
for (const row of parsed.slice(1)) { for (const row of parsed.slice(1)) {
const criteria = getCmsTeamCriteria(row[0]) const criteria = getCmsTeamCriteria(row[0], row[1])
if (!criteria) continue if (!criteria) continue
const ids = importedTeams const ids = importedTeams
.filter(team => team.ageClass === criteria.ageClass && (!criteria.teamNumber || team.teamNumber === criteria.teamNumber)) .filter(team => team.ageClass === criteria.ageClass && (!criteria.teamNumber || team.teamNumber === criteria.teamNumber))