Files
WKVS/html/intern/kampfrichter.php

1288 lines
58 KiB
PHP

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
// Add a higher memory limit
$baseDir = $_SERVER['DOCUMENT_ROOT'];
require_once $baseDir . '/../scripts/session_functions.php';
ini_wkvs_session(true);
$csrf_token = $_SESSION['csrf_token'] ?? '';
$access_granted_kampfrichter = check_user_permission('kampfrichter', true) ?? false;
$access_granted_wk_leitung = check_user_permission('wk_leitung', true) ?? false;
if (!$access_granted_kampfrichter):
$logintype = 'kampfrichter';
require $baseDir . '/../scripts/login/login.php';
$logintype = '';
else:
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/websocket/ws-create-token.php';
$type = 'kr';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true) {
echo 'Critical DB Error.';
exit;
}
$currentPage = 'kampfrichter';
require $baseDir . '/../scripts/kampfrichter/check-user-freigaben.php';
$current_wk_id = (int) db_get_variable($mysqli, $db_tabelle_var, ['current_wk_id']) ?: 0;
if ($current_wk_id < 1) {
http_response_code(400);
$message = 'Es wurde kein Wettkampf ausgewählt. Setzen unter: https://'. $_SERVER['HTTP_HOST'].'/intern/wk-leitung/wettkaempfe';
include $baseDir . "/error-pages/400.php";
exit;
}
$disciplines = db_select($mysqli, $db_tabelle_disziplinen, '*', '', [], 'start_index ASC');
$indexedArrayGeraete = array_column($disciplines, 'name', 'id');
$indexed_array_geraete_id_index = array_column($disciplines, 'start_index', 'id');
$indexed_array_geraete_index_id = array_flip($indexed_array_geraete_id_index);
$max_subabt = count($disciplines);
$selectedFreigabe = (!$isAdmin) ? $indexedArrayGeraete[intval($selectedFreigabeId)] ?? '' : 'Admin';
$current_year = date('Y'); // or you can set this dynamically as you want
$monat = date('n');
if ($monat > 6) {
$current_year = $current_year + 1;
}
$localPath = $_SERVER['DOCUMENT_ROOT'] . "/files/ranglisten/";
$wkName = db_get_var($mysqli, "SELECT `value` FROM $db_tabelle_var WHERE `name` = ?", ['wkName']);
$sortprio = [];
$audiofilesPersonen = db_select($mysqli, $db_tabelle_teilnehmende_audiofiles, '*');
$indexedAudiofiles = [];
foreach ($audiofilesPersonen as $sAf) {
$indexedAudiofiles[$sAf['person_id']][$sAf['geraet_id']] = $sAf['audiofile_id'];
}
$programmes = db_select($mysqli, $db_tabelle_kategorien, 'programm, `id`, `order_index`', 'aktiv = ?', ['1']);
$indexedProgrammIds = array_column($programmes, 'id', 'programm');
$indexedProgramme = array_column($programmes, null, 'programm');
$selected_view_admin = $_SESSION['view_type_admin'] ?? 'prog';
$prog_view_admin = (bool) ($selected_view_admin === 'prog' && $isAdmin);
$abt_view_admin = (bool) ($selected_view_admin === 'abt' && $isAdmin);
$live_view_admin = (bool) ($selected_view_admin === 'live' && $isAdmin);
$aktabt = (int) (db_get_variable($mysqli, $db_tabelle_var, ['wk_panel_current_abt']) ?? 1);
$akt_subabt_admin = (int) (db_get_variable($mysqli, $db_tabelle_var, ['wk_panel_current_subabt_admin']) ?? 1);
$maxvalue = db_get_var($mysqli, "SELECT `order_index` FROM $db_tabelle_gruppen ORDER BY `order_index` DESC LIMIT 1");
$res = $mysqli->query("SELECT * FROM $db_tabelle_wertungstypen");
$notenConfig = $res->fetch_all(MYSQLI_ASSOC);
$indexedNotenConfig = array_column($notenConfig, null, 'id');
$allAbts = db_select($mysqli, $db_tabelle_gruppen, '*', '', [], 'order_index ASC');
$indexedAbts = array_column($allAbts, null, 'id');
$personEinzahl = db_get_variable($mysqli, $db_tabelle_var, ['personEinzahl']);
if ($personEinzahl === null)
$personEinzahl = 'Person';
$personMehrzahl = db_get_variable($mysqli, $db_tabelle_var, ['personMehrzahl']);
if ($personMehrzahl === null)
$personMehrzahl = 'Personen';
// Custom Layout Abruf und Helper-Function für Aufbau
$json_type = ($isAdmin && !$live_view_admin) ? 'kampfrichter-admin' : 'kampfrichter-geraet';
$jsonstr = db_select($mysqli, $db_tabelle_tabellen_konfiguration, 'json', 'type_slug = ?', [$json_type], '', 1);
$data = json_decode($jsonstr[0]['json'] ?? '', true);
$headers = $data['header'] ?? [];
$bodyColumns = $data['body'] ?? [];
$personData = [
'geburtsdatum' => 'Geburtsdatum',
'name' => 'Name',
'vorname' => 'Vorname',
'verein' => 'Verein',
'programm' => 'Programm'
];
$timeZone = new \DateTimeZone('Europe/Zurich');
$formatter = new \IntlDateFormatter(
'de_CH',
\IntlDateFormatter::FULL,
\IntlDateFormatter::NONE,
$timeZone
);
$display_over_array = [];
function constructSingleValueSpanPublic($token, $type, $row, $selected_geraet_id = 0)
{
global $formatter;
global $personData;
global $arrayIndexedNoten;
global $selectedFreigabeId;
global $timeZone;
global $display_over_array;
global $indexedNotenConfig;
global $indexedProgramme;
$text = '';
$html = '';
$classes = 'singleValueSpan';
$bold = $token['bold'] ?? false;
$font_size = (int) ($token['fontSize'] ?? 0);
$min_display_width = (int) ($token['minDisplayWidth'] ?? 1) - 1;
$linked_el_uid = (int) ($token['linkedElUid'] ?? 0);
$uid = (int) ($token['uid'] ?? 0);
$style = '';
if ($font_size > 0) {
$style = ' style="font-size: ' . $font_size . 'px"';
}
if ($min_display_width > 0) {
$classes .= ' displayOver' . $min_display_width . 'px';
$display_over_array[] = $min_display_width;
}
$dataAttributes = 'data-bold="' . htmlspecialchars($bold) . '" data-uid="' . $uid . '"';
if ($linked_el_uid > 0) {
$dataAttributes .= ' data-linked-el-uid="' . $linked_el_uid . '"';
}
$geraet_id = $selected_geraet_id !== 0 ? $selected_geraet_id : $selectedFreigabeId;
switch ($type) {
case 'text':
$text = $token['text'] ?? '';
$classes .= ' staticText';
break;
case 'sortData':
$column = $token['column'] ?? '';
switch ($column) {
case "rang":
$classes .= ' rangField';
break;
case "startindex":
$text = $row['calculedstartindex'];
break;
}
break;
case 'personData':
$column = $token['column'] ?? '';
if ($column === 'jahrgang') {
$geburtsdatum = $row['geburtsdatum'] ?? '';
$date = new \DateTimeImmutable($geburtsdatum, $timeZone);
$formatter->setPattern('yyyy');
$text = $formatter->format($date);
} else {
$text = array_key_exists($column, $personData) ? $row[$column] ?? '' : '';
if ($column === 'geburtsdatum') {
$date = new \DateTimeImmutable($text, $timeZone);
$formatter->setPattern(($token['phpDateFormat'] ?? '' !== '') ? $token['phpDateFormat'] : 'd. MMMM YYYY');
$text = $formatter->format($date);
}
}
break;
case 'notenData':
$field_type_id = intval($token['field-type-id'] ?? 0);
$geraet_id = intval($token['geraet-id'] ?? 0);
$run = intval($token['run'] ?? 0);
$person_id = $row['id'];
$notenNullable = ($token['notenNullable'] ?? 'false') === 'true';
$dataAttributes .= ' data-field-type-id="' . $field_type_id . '"';
$dataAttributes .= ' data-geraet-id="' . $geraet_id . '"';
$dataAttributes .= ' data-person-id="' . $person_id . '"';
$dataAttributes .= ' data-run="' . $run . '"';
$dataAttributes .= ' data-noten-nullable="' . (($notenNullable) ? "true" : "false") . '"';
$text = $arrayIndexedNoten[$person_id][$geraet_id][$field_type_id][$run]['value'] ?? null;
if ($notenNullable && $text !== null && floatval($text) === 0.0) {
$text = ' ';
}
if ($text === null) {
$classes .= ' emtyPlaceholder';
$text = '-';
}
$classes .= ' changebleValue';
break;
case 'notenGeraetData':
$field_type_id = intval($token['field-type-id'] ?? 0);
$run = intval($token['run'] ?? 0);
$person_id = $row['id'];
$programm_id = $indexedProgramme[$row['programm']]['id'] ?? 0;
$runsJSON = json_decode($indexedNotenConfig[$field_type_id]['anzahl_laeufe_json'] ?? '', true) ?? [];
$max_run = $runsJSON[$geraet_id][$programm_id] ?? $runsJSON[$geraet_id]['all'] ?? $runsJSON['default'] ?? 0;
if ($run > $max_run) {
$classes .= ' nonExistentEl';
} else {
$notenNullable = ($token['notenNullable'] ?? 'false') === 'true';
$dataAttributes .= ' data-field-type-id="' . $field_type_id . '"';
$dataAttributes .= ' data-geraet-id="' . $geraet_id . '"';
$dataAttributes .= ' data-person-id="' . $person_id . '"';
$dataAttributes .= ' data-run="' . $run . '"';
$dataAttributes .= ' data-noten-nullable="' . (($notenNullable) ? "true" : "false") . '"';
$text = $arrayIndexedNoten[$person_id][$geraet_id][$field_type_id][$run]['value'] ?? null;
if ($notenNullable && $text !== null && floatval($text) === 0.0) {
$text = ' ';
}
if ($text === null) {
$classes .= ' emtyPlaceholder';
$text = '-';
}
$classes .= ' changebleValue';
}
break;
case "kampfrichterEls":
$id = intval($row["id"]);
$html = '<button class="editTurnerin" data-person-id="' . $id . '"
data-geraet-id="' . $geraet_id . '" aria-label="Bearbeiten"
title="Bearbeiten">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24"
width="24">
<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25z"
fill="#536467ff" />
<path
d="M20.71 7.04a1.003 1.003 0 0 0 0-1.42l-2.34-2.34a1.003 1.003 0 0 0-1.42 0l-1.83 1.83 3.75 3.75 1.84-1.82z"
fill="var(--bg-top)" />
</svg>
</button>';
}
?>
<span class="<?= $classes ?>" <?= $dataAttributes; ?><?= $style ?>><?= htmlspecialchars($text); ?><?= $html ?></span>
<?php }
require $baseDir . '/../scripts/kampfrichter/post-handler.php';
$dbprogramme = [];
$allprogrammeabt = [];
$allprogrammeabtstr = '';
$allprogrammeabtstrcleared = '';
if ($dbprogramme) {
foreach ($dbprogramme as $ind => $singledbprogramm) {
$sinleprogramm = $singledbprogramm['programm'];
if (!(in_array($sinleprogramm, $allprogrammeabt))) {
$allprogrammeabt[] = $sinleprogramm;
$allprogrammeabtstr .= $sinleprogramm . ', ';
}
}
$pos = strrpos($allprogrammeabtstr, ' ');
if ($pos !== false) {
$allprogrammeabtstrcleared = substr_replace($allprogrammeabtstr, '', $pos, 1);
}
if (mb_strlen($allprogrammeabtstrcleared) > 1) {
$allprogrammeabtstrcleared = mb_substr($allprogrammeabtstrcleared, 0, mb_strlen($allprogrammeabtstrcleared) - 1);
}
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="png" href="/intern/img/icon.png">
<title>Intern - Kampfrichter</title>
<link rel="stylesheet" href="/intern/css/kampfrichter.css">
<link rel="stylesheet" href="/intern/css/sidebar.css">
<link rel="stylesheet" href="/intern/css/custom-msg-display.css">
<link rel="stylesheet" href="/css/custom-display-editor-required-css.css">
<link href="/files/fonts/fonts.css" rel="stylesheet">
<script src="/intern/js/jquery/jquery-3.7.1.min.js"></script>
<script src="/intern/js/custom-msg-display.js"></script>
<link rel="stylesheet" href="/intern/css/user.css">
<?php
$topBg = '#24786d';
foreach ($disciplines as $d) {
if ($d['id'] == $selectedFreigabeId)
$topBg = $d['color_kampfrichter'];
}
$hex = str_replace('#', '', $topBg);
$channels = str_split($hex, 2);
$rgb_no_commas = hexdec($channels[0]) . ' ' . hexdec($channels[1]) . ' ' . hexdec($channels[2]);
?>
<style>
:root {
--bg-top:
<?php echo $topBg; ?>
;
--bg-top-raw:
<?php echo $rgb_no_commas; ?>
;
<?php if ($isAdmin): ?>
<?php foreach ($disciplines as $d): ?>
--color-<?= $d['name'] ?>:
<?= $d['color_kampfrichter'] . '10' ?>
;
<?php endforeach; ?>
<?php endif; ?>
}
<?php if ($isAdmin): ?>
<?php foreach ($disciplines as $d): ?>
.field<?= ucfirst($d['name']) ?> {
position: relative;
}
.field<?= ucfirst($d['name']) ?>:before {
content: "";
display: block;
position: absolute;
top: 0;
right: 0px;
height: 100%;
width: 100%;
background-color: var(--color-<?= $d['name'] ?>);
z-index: 0;
pointer-events: none;
}
';
<?php endforeach;
endif;
$unique_display_over_array = array_unique($display_over_array);
foreach ($unique_display_over_array as $s_size):
$s_size = (int) $s_size;
?>
@media (max-width:
<?= $s_size ?>
px) {
.displayOver<?= $s_size ?>px {
display: none !important;
}
}
<?php endforeach; ?>
</style>
<script>
let lastWrite = 0;
const interval = 200;
window.addEventListener('scroll', function () {
const now = Date.now();
if (now - lastWrite >= interval) {
sessionStorage.setItem('scrollY', window.scrollY);
lastWrite = now;
}
}, { passive: true });
window.addEventListener('load', function () {
const scrollY = sessionStorage.getItem('scrollY');
if (scrollY !== null) {
window.scrollTo(0, parseInt(scrollY, 10));
}
});
$( document ).ready(function() {
const $menuburger = $('.kampfrichterBurgerMenuDiv');
const $menudiv = $('.internMenuDiv');
const storageKey = "kampfrichterInternMenuOpen";
const isOpen = localStorage.getItem(storageKey) === "true";
if (isOpen) {
$menuburger.addClass("open");
$menudiv.addClass("open");
}
// Toggle menu on burger click
$menuburger.on("click", function () {
$menuburger.addClass("menuTransition");
$menudiv.addClass("menuTransition");
$menuburger.toggleClass("open");
$menudiv.toggleClass("open");
const isOpenEl = $menudiv.hasClass("open") && $menuburger.hasClass("open");
localStorage.setItem(storageKey, isOpenEl);
});
});
</script>
</head>
<body class="kampfrichter">
<?php
require $baseDir . '/../scripts/sidebar/sidebar.php';
// Berechnung des ausgewählten Startgerätes
$akt_subabt = ($isAdmin) ? $akt_subabt_admin : $_SESSION['currentsubabt'];
$itemsToLoop = [];
$indexedDisciplines = array_column($disciplines, null, 'id');
if ($isAdmin) {
foreach ($disciplines as $sd) {
$itemsToLoop[] = $sd;
}
} else {
$itemsToLoop[] = ['name' => $selectedFreigabe, 'id' => $selectedFreigabeId ?? null, 'audiofile' => $indexedDisciplines[$selectedFreigabeId ?? 0]['audiofile'] ?? 0];
}
if ($abt_view_admin) {
$whereClause = 'WHERE agg.abteilung > 0';
$params = [];
$orderBy = 't.id ASC';
} elseif (!$isAdmin) {
$base_index_from_user = $indexed_array_geraete_id_index[$selectedFreigabeId];
$startGeraetArrayIndex = $base_index_from_user - $akt_subabt + 1;
if ($startGeraetArrayIndex < 1) {
$startGeraetArrayIndex += $max_subabt;
}
$startgeindex = $indexed_array_geraete_index_id[$startGeraetArrayIndex];
$whereClause = 'WHERE agg.abteilung = ? AND agg.geraetId = ?';
$params = [$aktabt, $startgeindex];
$orderBy = 'agg.startIndex ASC';
} elseif ($live_view_admin) {
$whereClause = 'WHERE agg.abteilung = ?';
$params = [$aktabt];
$orderBy = 'agg.startIndex ASC';
} else {
$whereClause = '';
$params = [];
$orderBy = 't.id DESC';
}
$stmt = $mysqli->prepare("
SELECT
t.*,
agg.abteilung,
agg.startgeraet,
agg.startIndex,
agg.abtId,
agg.geraetId
FROM $db_tabelle_teilnehmende t
LEFT JOIN (
SELECT
ta.turnerin_id,
GROUP_CONCAT(DISTINCT a.order_index SEPARATOR ', ') AS abteilung,
GROUP_CONCAT(DISTINCT g.start_index SEPARATOR ', ') AS startgeraet,
ta.turnerin_index AS startIndex,
ta.abteilung_id AS abtId,
ta.geraet_id AS geraetId
FROM $db_tabelle_teilnehmende_gruppen ta
INNER JOIN $db_tabelle_gruppen a
ON a.id = ta.abteilung_id
LEFT JOIN $db_tabelle_disziplinen g
ON g.id = ta.geraet_id
GROUP BY ta.turnerin_id
) agg ON agg.turnerin_id = t.id
$whereClause
ORDER BY $orderBy
");
if (!empty($params)) {
$types = str_repeat("s", count($params));
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
$result = $stmt->get_result();
$entries = $result->fetch_all(MYSQLI_ASSOC);
$grouped = [];
function groop_by_key($array, $array_key, bool $int = false): array
{
$grouped = [];
if ($int) {
foreach ($array as $entry) {
$key = (int) $entry[$array_key];
$grouped[$key][] = $entry;
}
} else {
foreach ($array as $entry) {
$key = $entry[$array_key];
$grouped[$key][] = $entry;
}
}
return $grouped;
}
if (!$isAdmin || $abt_view_admin) {
$grouped = groop_by_key($entries, 'abtId', true);
} elseif ($live_view_admin) {
$grouped = groop_by_key($entries, 'geraetId', true);
} else {
$grouped = groop_by_key($entries, 'programm');
foreach ($grouped as $key => $group) {
$orderIndexes[$key] = $indexedProgramme[$key]['order_index'] ?? 10000;
}
if (isset($orderIndexes)) {
uksort($grouped, function ($a, $b) use ($orderIndexes) {
return $orderIndexes[$a] <=> $orderIndexes[$b];
});
}
}
$itemsToLoop = [];
$indexedDisciplines = array_column($disciplines, null, 'id');
if ($isAdmin) {
foreach ($disciplines as $sd) {
$itemsToLoop[] = $sd;
}
} else {
$itemsToLoop[] = ['name' => $selectedFreigabe, 'id' => $selectedFreigabeId ?? null, 'audiofile' => $indexedDisciplines[$selectedFreigabeId ?? 0]['audiofile'] ?? 0];
} ?>
<div class="internMenuDiv">
<div class="closeInternMenuMobileDiv"></div>
<div class="innerInternMenuDiv">
<?php
if ($isAdmin) {
$maxstyle_abt = ($aktabt == $maxvalue) ? 'background-color: rgba(68, 68, 68, 0.27); pointer-events:none;' : '';
$minstyle_abt = ($aktabt == 1) ? 'background-color: rgba(68, 68, 68, 0.27); pointer-events:none;' : '';
$maxstyle_subabt_admin = ($akt_subabt_admin == $max_subabt) ? 'background-color: rgba(68, 68, 68, 0.27); pointer-events:none;' : '';
$minstyle_subabt_admin = ($akt_subabt_admin == 1) ? 'background-color: rgba(68, 68, 68, 0.27); pointer-events:none;' : '';
?>
<div class="gruppennav">
<p>Aktuelle Gruppe </p>
<form action="/intern/kampfrichter" method="post">
<input type="hidden" name="csrf_token" id="prev_abt_nonce" value="<?= $csrf_token ?>">
<input type="hidden" name="prev_abt" value="-1">
<input type="submit" style="<?= $minstyle_abt ?>" name="prev_abt_submit" class="button_gruppe"
value="<">
</form>
<p><?= (int) $aktabt ?></p>
<form action="/intern/kampfrichter" method="post">
<input type="hidden" name="csrf_token" id="next_abt_nonce" value="<?= $csrf_token ?>">
<input type="hidden" name="next_abt" value="1">
<input type="submit" style="<?= $maxstyle_abt ?>" name="next_abt_submit" class="button_gruppe"
value=">">
</form>
<p> / <?= (int) $maxvalue ?></p>
</div>
<div class="gruppennav">
<p>Aktuelle Rotation </p>
<form action="/intern/kampfrichter" method="post">
<input type="hidden" name="csrf_token" id="prev_subabt_admin_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="<?= $minstyle_subabt_admin ?>" name="prev_subabt_admin_submit"
class="button_gruppe" value="<">
</form>
<p><?= (int) $akt_subabt_admin ?></p>
<form action="/intern/kampfrichter" method="post">
<input type="hidden" name="csrf_token" id="next_subabt_admin_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="<?= $maxstyle_subabt_admin ?>" name="next_subabt_admin_submit"
class="button_gruppe" value=">">
</form>
<p> / <?= (int) $max_subabt ?></p>
</div>
<?php } else {
$maxstyle = ($akt_subabt == $max_subabt) ? 'background-color: rgba(68, 68, 68, 0.27) !important; pointer-events:none !important;' : '';
$minstyle = ($akt_subabt == 1) ? 'background-color: rgba(68, 68, 68, 0.27) !important; pointer-events:none !important;' : '';
?>
<div class="gruppennav">
<p>Aktuelle Rotation </p>
<form action="/intern/kampfrichter" method="post">
<input type="hidden" name="csrf_token" id="prev_subabt_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="<?= $minstyle ?>" name="prev_subabt_submit" class="button_gruppe"
value="<">
</form>
<p><?= $akt_subabt ?></p>
<form action="/intern/kampfrichter" method="post">
<input type="hidden" name="csrf_token" id="next_subabt_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="<?= $maxstyle ?>" name="next_subabt_submit" class="button_gruppe"
value=">">
</form>
<p> / <?= $max_subabt ?></p>
</div>
<?php
}
if ($isAdmin): ?>
<?php if (!$prog_view_admin): ?>
<form method="post">
<input type="hidden" name="csrf_token" id="prog_view_admin_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="background-color: #003;" name="prog_view_admin_submit"
class="buttonNewAdminStyle" value="Nach Programmen sortieren">
</form>
<?php endif; ?>
<?php if (!$abt_view_admin): ?>
<form method="post">
<input type="hidden" name="csrf_token" id="abt_view_admin_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="background-color: #030;" name="abt_view_admin_submit"
class="buttonNewAdminStyle" value="Nach Abteilungen sortieren">
</form>
<?php endif; ?>
<?php if (!$live_view_admin): ?>
<form method="post" style="margin-bottom: 1em;">
<input type="hidden" name="csrf_token" id="live_view_admin_nonce" value="<?= $csrf_token ?>">
<input type="submit" style="background-color: #300;" name="live_view_admin_submit"
class="buttonNewAdminStyle" value="Aktuelle Personen anzeigen">
</form>
<?php endif; ?>
<?php else: ?>
<div class="horizontalLabelWrapper">
<span class="text_akt_abt">Aktuelle Rotaion Displays <?= $akt_subabt_admin ?> von <?= $max_subabt ?></span>
<span class="text_akt_abt">Aktuelle Gruppe <?= $aktabt ?> von <?= $maxvalue ?></span>
</div>
<?php endif; ?>
</div>
</div>
<div class="menuBg"></div>
<section class="bgSection">
<div class="headerDivKampfrichter">
<div class="headingPanelDiv">
<h2 class="headingPanel">Kampfrichterpanel</h2>
<h3 class="headingPanelGeraet"><?= $selectedFreigabe ?></h3>
</div>
<div class="menuWrapper">
<div class="kampfrichterBurgerMenuDiv">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"
stroke-linejoin="round">
<path
d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
</svg>
</div>
<?php sidebarRender('button') ?>
</div>
<?php if (!$isAdmin) { ?>
<script>
const currentsubabt = <?= (int) $akt_subabt ?>;
const maxsubabt = <?= (int) $max_subabt ?>;
document.addEventListener("keydown", (e) => {
// Example: Arrow Left = previous, Arrow Right = next
const isOptionOrAlt = e.altKey || e.metaKey;
if (e.key === "ArrowLeft" && currentsubabt > 1 && isOptionOrAlt) {
sendSubAbt("prev_subabt");
} else if (e.key === "ArrowRight" && currentsubabt < maxsubabt && isOptionOrAlt) {
sendSubAbt("next_subabt");
}
});
function sendSubAbt(action) {
const formData = new FormData();
formData.append(action, 1);
formData.append(action + "_submit", 1);
fetch("/intern/kampfrichter", {
method: "POST",
body: formData,
credentials: "same-origin"
})
.then(() => {
location.reload();
})
.catch(err => console.error("POST failed:", err));
}
</script>
<?php } ?>
</div>
<?php
echo sidebarRender('modal');
?>
<div class="div_edit_values_user_outer">
<div class="div_edit_values_user" style="display: none;">
<h3 class="heading_fv_selturnerin" tabindex="-1">
<?= $personEinzahl ?>:
<span class="current-turnerin-name"></span>
</h3>
<div class="div_edit_values_all_gereate">
<?php foreach ($itemsToLoop as $d):
if ($d['id'] === null) {
continue;
} ?>
<div class="all_vaules_div">
<?php if ($isAdmin): ?>
<h4><?= $d['name'] ?></h4>
<?php endif; ?>
<div class="allNotentable">
<div class="singleNotentable">
<?php foreach ($notenConfig as $nc):
$isProGeraet = (intval($nc['pro_geraet']) === 1);
$allowedGeraete = !empty($nc['geraete_json']) ? json_decode($nc['geraete_json'], true) : [];
if (!$isProGeraet && !in_array($d['id'], $allowedGeraete)) {
continue;
}
$disabled = ($nc['type'] === 'berechnung') ? 'disabled' : '';
?>
<table class="titleWidthNormalInput editkampfrichter_user note-container hidden"
data-note-id="<?= $nc['id'] ?>"
data-runs-config='<?= htmlspecialchars($nc['anzahl_laeufe_json'] ?? '{"default":1}') ?>'>
<thead>
<tr>
<th class="<?= $nc['id'] ?>-field-th note-name-header"><?= $nc['name'] ?>
</th>
</tr>
</thead>
<tbody>
<tr class="inputs-row">
<td class="nopadding input-cell-run-1">
<input type="number" class="ajax-input fullinput changebleValue"
data-person-id="" data-field-type-id="<?= $nc['id'] ?>"
data-geraet-id="<?= $d['id'] ?>"
data-programm-id="<?= $indexedProgrammIds[$d['programm'] ?? ''] ?? 0 ?>"
data-run="1" value="" min="0" max="20" step="0.005" <?= $disabled ?>>
</td>
</tr>
</tbody>
</table>
<?php endforeach ?>
</div>
</div>
<div class="allControlsDiv">
<div class="editUserButtons">
<input type="button" class="submit-display-turnerin" data-person-id=""
data-geraet-id="<?= $d['id'] ?>" value="<?= $personEinzahl ?> anzeigen">
<div class="div-submit-display-start">
<input type="button" class="submit-display-start start" data-person-id=""
data-geraet-id="<?= $d['id'] ?>" data-type="1" value="Startfreigabe erteilen">
<input type="button" class="submit-display-start stopp" data-person-id=""
data-geraet-id="<?= $d['id'] ?>" data-type="0" value="Startfreigabe enziehen">
</div>
<div class="div-submit-display-result">
<input type="button" class="submit-display-result" data-person-id=""
data-geraet-id="<?= $d['id'] ?>" data-run="1" value="Ergebnis anzeigen">
</div>
</div>
<?php if (intval($d["audiofile"]) === 1): ?>
<div class="playcontrolDiv">
<input type="button" class="submit-musik-start" data-id="" data-geraet-id="<?= $d['id'] ?>"
value="Musik starten">
<input type="button" class="submit-musik-stopp" data-geraet-id="<?= $d['id'] ?>"
value="Musik stoppen">
</div>
<?php endif; ?>
</div>
<?php if (!$isAdmin): ?>
<h5 class="heading_fv_nextturnerin">Nächste Person:</h5>
<a class="fv_nextturnerin editTurnerin" data-person-id="" data-geraet-id="<?= $d['id'] ?>"></a>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="allTurnerinenDiv">
<?php if (!(!empty($programmes) && is_array($programmes))): ?>
<h3>Eingabetool noch nicht freigeschalten</h3>
<?php endif; ?>
<?php if (!$live_view_admin): ?>
<h3 class="heading_fv_alleturnerinnen">Alle <?= $personMehrzahl ?>:</h3>
<?php endif; ?>
<div class="allAbtContainer">
<?php
$total_count = 0;
if (empty($grouped)): ?>
<p>Noch keine Datensätze vorhanden.</p>
<?php exit;
endif;
$ids = array_column($entries, 'id');
if (!empty($ids)) {
// Create placeholders: ?,?,?
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$sql = "SELECT `person_id`, `note_bezeichnung_id`, `geraet_id`, `run_number`, `value`
FROM $db_tabelle_wertungen
WHERE `wk_id` = ? AND `person_id` IN ($placeholders)";
$stmt = $mysqli->prepare($sql);
// In PHP 8.1+, you can simply pass an array to execute()
// We merge the year with the IDs into one flat array
$params = array_merge([$current_wk_id], $ids);
$stmt->execute($params);
$noten = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
}
$rangNote = intval(db_get_var($mysqli, "SELECT `value` FROM $db_tabelle_var WHERE `name` = ?", ['rangNote']));
$orderBestRang = db_get_var($mysqli, "SELECT `value` FROM $db_tabelle_var WHERE `name` = ?", ['orderBestRang']);
$okValuesOrderBestRang = ["ASC", "DESC"];
$rangOrderOk = in_array($orderBestRang, $okValuesOrderBestRang) && intval($rangNote) > 0;
$notenIndexed = [];
foreach ($noten as $sn) {
$notenIndexed[$sn['person_id']][$sn['geraet_id']][$sn['note_bezeichnung_id']][$sn['run_number']] = $sn['value'];
}
$stmt->close();
// Extended Disciplines, contains the 0 disc
$disciplinesExtended = array_merge(
[["id" => 0, "name" => "None"]],
$disciplines
);
foreach ($grouped as $abteilung => $entries_group):
// Nur sortieren, wenn der Benutzer nicht 'Admin' ist
if (!$isAdmin || $live_view_admin) {
$entries_with_calculated_index = [];
// Optional: Vorab-Caching der MAX-Indices, um DB-Abfragen im Loop zu vermeiden
// (Nur aktivieren, wenn $entries_group sehr groß ist und Performance-Probleme auftreten)
$maxStartIndexCache = [];
foreach ($entries_group as $row) {
$old_geraet_id = $row['geraetId'];
if ($live_view_admin) {
$old_geraet_index = $indexed_array_geraete_id_index[$row['geraetId']];
$shifted_geraet_index = $old_geraet_index + $akt_subabt - 1;
if ($shifted_geraet_index > $max_subabt) {
$shifted_geraet_index -= $max_subabt;
}
$row['geraetId'] = $indexed_array_geraete_index_id[$shifted_geraet_index];
}
$rohstartindex = intval($row['startIndex']);
$abtId = intval($row['abtId']);
// Hole maxStartIndex (mit Caching-Logik optional)
if (!isset($maxStartIndexCache["$abtId-$old_geraet_id "])) {
$maxStartIndexCache["$abtId-$old_geraet_id"] = db_get_var($mysqli, "SELECT COUNT(*) FROM `$db_tabelle_teilnehmende_gruppen` WHERE abteilung_id = ? AND geraet_id = ?", [$abtId, $old_geraet_id]);
}
$maxstartindex = $maxStartIndexCache["$abtId-$old_geraet_id"];
// Sicherheit: Vermeiden Sie Division durch Null oder Modulo durch 0
if ($maxstartindex < 1) {
$maxstartindex = 1;
}
// The order shift depends on the number of rotations the group has made
$rotation_shift = $akt_subabt - 1;
$calculedstartindex = $rohstartindex - $rotation_shift;
// Sicherstellen, dass das Ergebnis positiv ist (PHP Modulo kann negative Ergebnisse liefern)
// Wenn das Ergebnis negativ ist, addieren wir maxstartindex
if ($calculedstartindex < 1) {
$calculedstartindex += $maxstartindex;
}
// Kopie der Zeile erstellen, um Originaldaten nicht zu verändern
$row['calculedstartindex'] = $calculedstartindex;
$entries_with_calculated_index[] = $row;
}
// Sortieren nach dem berechneten Startindex
usort($entries_with_calculated_index, fn($a, $b) => $a['calculedstartindex'] <=> $b['calculedstartindex']);
$entries_to_display = $entries_with_calculated_index;
} else {
$entries_to_display = $entries_group;
}
$arrayIndexedNoten = [];
foreach ($entries_group as $row):
if ($isAdmin && $rangOrderOk) {
$rangNotenArray[$indexedProgrammIds[$row['programm'] ?? ''] ?? ''][$row['id']] = isset($notenIndexed[$row['id']][0][$rangNote][1]) ? (float) $notenIndexed[$row['id']][0][$rangNote][1] : null;
}
foreach ($disciplinesExtended as $discipline):
// Check if the current user/admin is allowed to see this specific discipline
if ($discipline['id'] === 0 || $selectedFreigabeId == $discipline['id'] || $isAdmin):
// 2. Now iterate through the scoring configurations for this discipline
foreach ($notenConfig as $snC) {
if (intval($snC['pro_geraet']) === 1 && intval($discipline['id']) === 0) {
continue;
}
if (intval($snC['pro_geraet']) !== 1) {
$allowedGeraete = !empty($snC['geraete_json']) ? json_decode($snC['geraete_json'], true) : [];
if (!in_array($discipline['id'], $allowedGeraete)) {
continue;
}
}
$defaultValue = $snC['default_value'] ?? 0;
$runsJSON = !empty($snC['anzahl_laeufe_json']) ? json_decode($snC['anzahl_laeufe_json'], true) : [];
$runs = $runsJSON[$discipline['id']][$indexedProgrammIds[$row['programm'] ?? ''] ?? ''] ?? $runsJSON[$discipline['id']]['all'] ?? $runsJSON["default"] ?? 1;
for ($r = 1; $r <= $runs; $r++):
$note = $notenIndexed[$row['id']][$discipline['id']][$snC['id']][$r] ?? null;
$normalizedNote = ($note !== null) ? number_format($note, $snC['nullstellen'] ?? 2) : null;
$arrayIndexedNoten[intval($row['id'])][intval($discipline['id'])][intval($snC['id'])][intval($r)] = ["value" => $normalizedNote];
endfor;
}
endif;
endforeach;
endforeach;
$table_data_geraet_label = '';
$extra_table_classes = '';
if ($live_view_admin) {
$shifted_geraet_index = $indexed_array_geraete_id_index[$abteilung] + $akt_subabt - 1;
if ($shifted_geraet_index > $max_subabt) {
$shifted_geraet_index -= $max_subabt;
}
$shifted_geraet_id = $indexed_array_geraete_index_id[$shifted_geraet_index];
$table_data_geraet_label = ' data-geraet-index="' . $shifted_geraet_index . '"';
$extra_table_classes = ' shiftedGeraetTable';
}
?>
<div class="singleAbtDiv<?= $extra_table_classes ?>" <?= $table_data_geraet_label ?>>
<?php if ($isAdmin): ?>
<h2 class="titleSingleAbt">
<?php if ($abt_view_admin): ?>
<?= $indexedAbts[$abteilung]['name'] ?? $abteilung ?>
<?php elseif ($live_view_admin): ?>
<?= $indexedDisciplines[$shifted_geraet_id]['name'] ?? $shifted_geraet_id ?>
<?php else: ?>
<?php $ranglisten_filename = str_replace(" ", "_", $wkName) . "_Ergebnisse_" . $abteilung . "_" . $current_year . ".pdf"; ?>
<?= $abteilung ?>
<span
class="rangliseOnlineSpan <?= (!file_exists($localPath . $ranglisten_filename)) ? 'hidden' : '' ?>">
-
<span style="color:#378d37">Rangliste Online</span>
</span>
<?php endif; ?>
</h2>
<?php if ($abt_view_admin): ?>
<span><?= $indexedAbts[$abteilung]['order_index'] ?? 'N/A' ?>. Abteilung</span>
<?php endif; ?>
<?php endif; ?>
<div class="tableWraperOverflowY">
<table class="widefat striped wkvsTabelle customDisplayEditorTable">
<thead>
<tr>
<?php foreach ($headers as $header_data): ?>
<?php
$min_display_width = ($header_data['minDisplayWidth'] ?? 1) - 1;
$class = "";
if ($min_display_width > 0) {
$class = 'displayOver' . $min_display_width . 'px';
$display_over_array[] = $min_display_width;
}
?>
<th class="<?= $class ?>">
<?= htmlspecialchars($header_data['title']) ?>
</th>
<?php endforeach; ?>
</tr>
</thead>
<tbody data-programm-id="<?= $indexedProgrammIds[$abteilung] ?? '' ?>">
<?php foreach ($entries_to_display as $row): ?>
<?php $geraet_id_for_live_view = $live_view_admin ? ((int) $row['geraetId']) : 0 ?>
<tr data-person-id="<?= $row['id'] ?>"
class="<?= $row['bezahltoverride'] == 4 || ($row['bezahlt'] == 4 && $row['bezahltoverride'] == 0) ? '' : 'notpaid' ?>">
<?php foreach ($bodyColumns as $ind => $columnTokens): ?>
<?php
$class = '';
if (isset($headers[$ind]['minDisplayWidth']) && $headers[$ind]['minDisplayWidth'] > 1) {
$min_display_width = ($headers[$ind]['minDisplayWidth'] ?? 1) - 1;
$class = 'displayOver' . $min_display_width . 'px';
$display_over_array[] = $min_display_width;
}
?>
<td class=<?= $class ?>>
<span class="tdSpan">
<?php
foreach ($columnTokens as $token):
$type = $token['type'] ?? '';
if ($type === 'layoutEls'):
$column = $token['column'];
$content = $token['content'] ?? []; ?>
<div class="<?= $column ?>LayoutEl">
<?php foreach ($content as $layout_row): ?>
<span class="<?= $column ?>LayoutElRow">
<?php foreach ($layout_row as $el):
constructSingleValueSpanPublic($el, $el['type'], $row, $geraet_id_for_live_view);
endforeach; ?>
</span>
<?php endforeach; ?>
</div>
<?php else:
constructSingleValueSpanPublic($token, $type, $row, $geraet_id_for_live_view);
endif;
endforeach; ?>
</span>
</td>
<?php endforeach;
$count = count($entries_to_display);
?>
</tr>
<?php endforeach;
$total_count += $count; ?>
</tbody>
</table>
</div>
<?php if ($isAdmin): ?>
<p><?= $count ?> <?= ($count > 1) ? $personMehrzahl : $personEinzahl ?></p>
<?php endif; ?>
<?php if ($isAdmin): ?>
<div class="adminButtonDiv">
<?php if ($prog_view_admin): ?>
<button data-field_type="downloadRangliste" data-id="<?= $abteilung ?>"
class="buttonRangliste ranglisteExport blackBtn">
Rangliste (PDF) herunterladen
</button>
<?php $fileUploaded = file_exists($localPath . $ranglisten_filename); ?>
<button data-field_type="updateServerRangliste" data-id="<?= $abteilung ?>"
class="buttonRangliste ranglisteExport blackBtn">
Rangliste (PDF) auf Fileserver
<span class="uploadRanglisteText <?= ($fileUploaded) ? 'hidden' : '' ?>">
veröffentlichen
</span>
<span class="updateRanglisteText <?= (!$fileUploaded) ? 'hidden' : '' ?>">
aktualisieren
</span>
</button>
<button data-field_type="upload_programm" data-id="<?= $abteilung ?>"
class="buttonRangliste ranglisteDelete blackBtn <?= (!$fileUploaded) ? 'hidden' : '' ?>">
Rangliste (PDF) von Fileserver löschen
</button>
<?php if ($access_granted_wk_leitung) : ?>
<button data-programm-id="<?= $indexedProgrammIds[$abteilung] ?>"
class="deleteNotenAbt blackBtn">
Alle Noteneinträge löschen
</button>
<?php endif; ?>
<?php elseif ($abt_view_admin): ?>
<button data-abteilung-id="<?= $abteilung ?>" class="buttonRangliste blackBtn protokollExport">
Protokoll (PDF) herunterladen
</button>
<button data-abteilung-id="<?= $abteilung ?>" class="buttonRangliste blackBtn protokollDeleteEntries">
Protokolleinträge für Abteilung löschen
</button>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php if ($isAdmin): ?>
<p style="font-weight:600; margin: 0px;">Gesamt: <?= $total_count ?>
<?= ($total_count > 1) ? $personMehrzahl : $personEinzahl ?>
</p>
<?php endif; ?>
</div>
<div class="divLiveSyncronisation">
<h2 class="heading-pannel flexRow" id="wsInfo">Live Synchronsation: <span class="fullHeightRectangle"
id="wsInfoRectangle"></span></h2>
</div>
</section>
<script>
window.FREIGABE = "<?= $selectedFreigabeId; ?>";
window.CSDR_TOKEN = "<?= $csrf_token; ?>";
window.WS_ACCESS_TOKEN = "<?= generateWSAdminToken('kampfrichter', $selectedFreigabeId) ?>";
window.AKTUELLES_JAHR = "<?= $current_year ?>";
<?php if ($isAdmin): ?>
window.RANG_NOTEN_ARRAY = '<?= json_encode($rangNotenArray, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>';
window.RANG_NOTE_ID = "<?= $rangNote ?>";
window.RANG_SORT = "<?= $orderBestRang ?>";
<?php
$ws_Message_json = $_SESSION['ws_Message_json'] ?? '';
$_SESSION['ws_Message_json'] = '';
?>
window.WS_MESSAGE = '<?= $ws_Message_json ?? '' ?>';
<?php endif; ?>
</script>
<script src="/intern/scripts/kampfrichter/js/js-kampfrichter-normal.js"></script>
<?php if ($isAdmin): ?>
<script src="/intern/scripts/kampfrichter/js/js-kampfrichter-admin.js"></script>
<?php endif; ?>
<?php endif; ?>
<?php if (isset($form_message) && $form_message !== ''): ?>
<script>displayMsg(1, "'.$form_message.'")</script>
<?php endif; ?>
</body>
</html>