Aktualisiere die Version auf 1.8.10 und füge Vereinsrang (QTTR / TTR) zur QTTR-Tabelle hinzu. Implementiere die Logik zur Berechnung und Sortierung der Vereinsränge in den API- und Import-Skripten.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "harheimertc-website",
|
"name": "harheimertc-website",
|
||||||
"version": "1.8.9",
|
"version": "1.8.10",
|
||||||
"description": "Moderne Webseite für den Harheimer Tischtennis Club",
|
"description": "Moderne Webseite für den Harheimer Tischtennis Club",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-500">
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-500">
|
||||||
Rang
|
Vereinsrang<br>(QTTR / TTR)
|
||||||
</th>
|
</th>
|
||||||
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-500">
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-500">
|
||||||
Spieler
|
Spieler
|
||||||
@@ -69,7 +69,9 @@
|
|||||||
:class="isOwnRow(row.playerName) ? 'bg-primary-100' : ''"
|
:class="isOwnRow(row.playerName) ? 'bg-primary-100' : ''"
|
||||||
>
|
>
|
||||||
<td class="px-4 py-3 text-sm text-gray-600">
|
<td class="px-4 py-3 text-sm text-gray-600">
|
||||||
{{ row.rank ?? '–' }}
|
<span :title="clubRankTitle(row)">
|
||||||
|
{{ formatClubRank(row) }}
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3">
|
<td class="px-4 py-3">
|
||||||
<div :class="['font-medium', getPlayerNameClass(row)]">
|
<div :class="['font-medium', getPlayerNameClass(row)]">
|
||||||
@@ -133,6 +135,20 @@ function isOwnRow(playerName) {
|
|||||||
return normalizeName(playerName) === current
|
return normalizeName(playerName) === current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatClubRank(row) {
|
||||||
|
const qttrRank = row.clubQttrRank
|
||||||
|
const ttrRank = row.clubTtrRank
|
||||||
|
if (qttrRank == null) return '–'
|
||||||
|
return ttrRank == null ? String(qttrRank) : `${qttrRank} (${ttrRank})`
|
||||||
|
}
|
||||||
|
|
||||||
|
function clubRankTitle(row) {
|
||||||
|
if (row.clubQttrRank == null) return 'Keine QTTR-Platzierung verfügbar'
|
||||||
|
return row.clubTtrRank == null
|
||||||
|
? `QTTR-Platzierung im Verein: ${row.clubQttrRank}`
|
||||||
|
: `QTTR-Platzierung im Verein: ${row.clubQttrRank}; TTR-Platzierung im Verein: ${row.clubTtrRank}`
|
||||||
|
}
|
||||||
|
|
||||||
function getPlayerNameClass(row) {
|
function getPlayerNameClass(row) {
|
||||||
const minor = isMinor(row.birthdate)
|
const minor = isMinor(row.birthdate)
|
||||||
if (minor && isMaleGender(row.gender)) return 'text-blue-400'
|
if (minor && isMaleGender(row.gender)) return 'text-blue-400'
|
||||||
|
|||||||
@@ -37,6 +37,26 @@ function buildBirthdateLookup(entries) {
|
|||||||
return lookup
|
return lookup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addClubRanks(rows) {
|
||||||
|
const addRankFor = (valueKey, rankKey) => {
|
||||||
|
rows
|
||||||
|
.filter((row) => row[valueKey] != null)
|
||||||
|
.sort((a, b) => b[valueKey] - a[valueKey] || String(a.playerName || '').localeCompare(String(b.playerName || ''), 'de'))
|
||||||
|
.forEach((row, index) => {
|
||||||
|
row[rankKey] = index + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
addRankFor('currentQttr', 'clubQttrRank')
|
||||||
|
addRankFor('currentTtr', 'clubTtrRank')
|
||||||
|
|
||||||
|
return rows.sort((a, b) =>
|
||||||
|
(a.clubQttrRank ?? Number.POSITIVE_INFINITY) - (b.clubQttrRank ?? Number.POSITIVE_INFINITY)
|
||||||
|
|| (a.clubTtrRank ?? Number.POSITIVE_INFINITY) - (b.clubTtrRank ?? Number.POSITIVE_INFINITY)
|
||||||
|
|| String(a.playerName || '').localeCompare(String(b.playerName || ''), 'de')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '')
|
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '')
|
||||||
if (!token || !verifyToken(token)) {
|
if (!token || !verifyToken(token)) {
|
||||||
@@ -73,16 +93,16 @@ export default defineEventHandler(async (event) => {
|
|||||||
].flatMap(entry => [entry?.name, `${entry?.firstName || ''} ${entry?.lastName || ''}`.trim()]).map(normalizeName).filter(Boolean))
|
].flatMap(entry => [entry?.name, `${entry?.firstName || ''} ${entry?.lastName || ''}`.trim()]).map(normalizeName).filter(Boolean))
|
||||||
const birthdateLookup = buildBirthdateLookup([...visibleManualMembers, ...visibleUsers])
|
const birthdateLookup = buildBirthdateLookup([...visibleManualMembers, ...visibleUsers])
|
||||||
|
|
||||||
|
const rankedRows = addClubRanks(Array.isArray(payload.rows) ? payload.rows.map(row => ({ ...row })) : [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...payload,
|
...payload,
|
||||||
rows: Array.isArray(payload.rows)
|
rows: rankedRows
|
||||||
? payload.rows
|
|
||||||
.filter(row => !hiddenNames.has(normalizeName(row.playerName)))
|
.filter(row => !hiddenNames.has(normalizeName(row.playerName)))
|
||||||
.map((row) => ({
|
.map((row) => ({
|
||||||
...row,
|
...row,
|
||||||
birthdate: birthdateLookup.get(normalizeName(row.playerName)) || row.birthdate || ''
|
birthdate: birthdateLookup.get(normalizeName(row.playerName)) || row.birthdate || ''
|
||||||
}))
|
}))
|
||||||
: []
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error?.code === 'ENOENT') {
|
if (error?.code === 'ENOENT') {
|
||||||
@@ -98,4 +118,4 @@ export default defineEventHandler(async (event) => {
|
|||||||
message: 'Fehler beim Laden der QTTR-Werte.'
|
message: 'Fehler beim Laden der QTTR-Werte.'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -67,6 +67,26 @@ function normalizeGender(value) {
|
|||||||
return normalized || null
|
return normalized || null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addClubRanks(rows) {
|
||||||
|
const addRankFor = (valueKey, rankKey) => {
|
||||||
|
rows
|
||||||
|
.filter((row) => row[valueKey] != null)
|
||||||
|
.sort((a, b) => b[valueKey] - a[valueKey] || String(a.playerName || '').localeCompare(String(b.playerName || ''), 'de'))
|
||||||
|
.forEach((row, index) => {
|
||||||
|
row[rankKey] = index + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
addRankFor('currentQttr', 'clubQttrRank')
|
||||||
|
addRankFor('currentTtr', 'clubTtrRank')
|
||||||
|
|
||||||
|
return rows.sort((a, b) =>
|
||||||
|
(a.clubQttrRank ?? Number.POSITIVE_INFINITY) - (b.clubQttrRank ?? Number.POSITIVE_INFINITY)
|
||||||
|
|| (a.clubTtrRank ?? Number.POSITIVE_INFINITY) - (b.clubTtrRank ?? Number.POSITIVE_INFINITY)
|
||||||
|
|| String(a.playerName || '').localeCompare(String(b.playerName || ''), 'de')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function extractTableBlocks(html) {
|
function extractTableBlocks(html) {
|
||||||
return [...String(html || '').matchAll(/<table\b[^>]*>[\s\S]*?<\/table>/gi)].map((match) => match[0])
|
return [...String(html || '').matchAll(/<table\b[^>]*>[\s\S]*?<\/table>/gi)].map((match) => match[0])
|
||||||
}
|
}
|
||||||
@@ -190,7 +210,7 @@ export async function importQttrValues(options = {}) {
|
|||||||
throw new Error('QTTR-Tabelle ist leer oder unvollständig')
|
throw new Error('QTTR-Tabelle ist leer oder unvollständig')
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedRows = rows.map((cells) => deriveQttrFields(headers, cells))
|
const parsedRows = addClubRanks(rows.map((cells) => deriveQttrFields(headers, cells)))
|
||||||
const payload = {
|
const payload = {
|
||||||
format: 'harheimertc.qttr.v1',
|
format: 'harheimertc.qttr.v1',
|
||||||
importedAt: new Date().toISOString(),
|
importedAt: new Date().toISOString(),
|
||||||
@@ -243,6 +263,8 @@ async function importAuthenticatedTtrValues(connection) {
|
|||||||
})
|
})
|
||||||
}).filter(row => row.playerName && (row.currentTtr != null || row.currentQttr != null))
|
}).filter(row => row.playerName && (row.currentTtr != null || row.currentQttr != null))
|
||||||
|
|
||||||
|
addClubRanks(rows)
|
||||||
|
|
||||||
if (!rows.length) throw new Error('Keine verwertbaren TTR-Werte in der myTischtennis-Rangliste gefunden.')
|
if (!rows.length) throw new Error('Keine verwertbaren TTR-Werte in der myTischtennis-Rangliste gefunden.')
|
||||||
const previousQttrSignature = qttrListSignature(previousPayload.rows)
|
const previousQttrSignature = qttrListSignature(previousPayload.rows)
|
||||||
const nextQttrSignature = qttrListSignature(rows)
|
const nextQttrSignature = qttrListSignature(rows)
|
||||||
|
|||||||
Reference in New Issue
Block a user