Upload files to "includes"
This commit is contained in:
403
includes/admin-teilnehmer.php
Normal file
403
includes/admin-teilnehmer.php
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
<?php
|
||||||
|
function kc_teilnehmer_page() {
|
||||||
|
global $wpdb;
|
||||||
|
$prefix = $wpdb->prefix;
|
||||||
|
kc_admin_tabs('kc_teilnehmer');
|
||||||
|
// Alle Wahlen + Workshops für Dropdowns und Validierung
|
||||||
|
$all_wahlen = $wpdb->get_results("SELECT id, name, anzahl_einheiten FROM {$prefix}kc_wahlen WHERE deleted=0 ORDER BY id DESC");
|
||||||
|
$all_workshops = $wpdb->get_results("SELECT id, name FROM {$prefix}kc_workshops ORDER BY name");
|
||||||
|
|
||||||
|
// Map of workshop id => name for quick lookup in overview
|
||||||
|
$workshops_map = [];
|
||||||
|
if (!empty($all_workshops)) {
|
||||||
|
foreach ($all_workshops as $ws) {
|
||||||
|
$workshops_map[intval($ws->id)] = $ws->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build map of wahl -> phases + workshops (for JS)
|
||||||
|
$wahl_map = [];
|
||||||
|
foreach($all_wahlen as $w) {
|
||||||
|
$wahl_map[intval($w->id)] = ['phases' => max(1,intval($w->anzahl_einheiten)), 'workshops' => []];
|
||||||
|
}
|
||||||
|
if (!empty($all_workshops)) {
|
||||||
|
foreach($all_workshops as $ws) {
|
||||||
|
$ww = $wpdb->get_col($wpdb->prepare("SELECT wahl_id FROM {$prefix}kc_wahl_workshops WHERE workshop_id=%d", $ws->id));
|
||||||
|
if (!empty($ww)) {
|
||||||
|
foreach($ww as $wid) {
|
||||||
|
if (isset($wahl_map[intval($wid)])) {
|
||||||
|
$wahl_map[intval($wid)]['workshops'][] = ['id'=>intval($ws->id),'name'=>$ws->name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teilnehmer l<>schen
|
||||||
|
if (isset($_GET['delete_teilnehmer'])) {
|
||||||
|
$tid = intval($_GET['delete_teilnehmer']);
|
||||||
|
$wpdb->delete("{$prefix}kc_teilnehmer", ['id' => $tid]);
|
||||||
|
echo '<div class="notice notice-success">Teilnehmer gel<65>scht!</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teilnehmer speichern (neu/<2F>ndern)
|
||||||
|
if (isset($_POST['kc_teilnehmer_save'])) {
|
||||||
|
// sanitize inputs
|
||||||
|
$vorname = sanitize_text_field($_POST['vorname']);
|
||||||
|
$nachname = sanitize_text_field($_POST['nachname']);
|
||||||
|
$wahl_id_post = intval($_POST['wahl_id']);
|
||||||
|
$phase_post = intval($_POST['phase']);
|
||||||
|
$w1 = intval($_POST['wunsch1']);
|
||||||
|
$w2 = intval($_POST['wunsch2']);
|
||||||
|
$w3 = intval($_POST['wunsch3']);
|
||||||
|
|
||||||
|
// Server-side validation: duplicate name in same Wahl (exclude self on edit)
|
||||||
|
$norm_v = mb_strtolower(trim($vorname));
|
||||||
|
$norm_n = mb_strtolower(trim($nachname));
|
||||||
|
if (!empty($_POST['tid'])) {
|
||||||
|
$exclude_id = intval($_POST['tid']);
|
||||||
|
$exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$prefix}kc_teilnehmer WHERE LOWER(TRIM(vorname))=%s AND LOWER(TRIM(nachname))=%s AND wahl_id=%d AND id<>%d", $norm_v, $norm_n, $wahl_id_post, $exclude_id));
|
||||||
|
} else {
|
||||||
|
$exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$prefix}kc_teilnehmer WHERE LOWER(TRIM(vorname))=%s AND LOWER(TRIM(nachname))=%s AND wahl_id=%d", $norm_v, $norm_n, $wahl_id_post));
|
||||||
|
}
|
||||||
|
if ($exists && $exists > 0) {
|
||||||
|
echo '<div class="notice notice-error">Diese Kombination aus Vorname und Nachname existiert bereits für diese Wahl.</div>';
|
||||||
|
} else {
|
||||||
|
// validate phase within wahl
|
||||||
|
$wahl_row = $wpdb->get_row($wpdb->prepare("SELECT anzahl_einheiten FROM {$prefix}kc_wahlen WHERE id=%d", $wahl_id_post));
|
||||||
|
$max_ph = $wahl_row ? max(1,intval($wahl_row->anzahl_einheiten)) : 1;
|
||||||
|
if ($phase_post < 1 || $phase_post > $max_ph) {
|
||||||
|
echo '<div class="notice notice-error">Ungültige Phase für die gewählte Wahl.</div>';
|
||||||
|
} else {
|
||||||
|
// validate that selected workshops belong to the chosen wahl (if mapping exists)
|
||||||
|
$valid_ws = [];
|
||||||
|
$ww_rows = $wpdb->get_col($wpdb->prepare("SELECT workshop_id FROM {$prefix}kc_wahl_workshops WHERE wahl_id=%d", $wahl_id_post));
|
||||||
|
if (!empty($ww_rows)) foreach($ww_rows as $r) $valid_ws[] = intval($r);
|
||||||
|
// if mapping exists, enforce membership
|
||||||
|
$check_membership = function($wid) use ($valid_ws) {
|
||||||
|
if (empty($valid_ws)) return true; // no mapping -> allow
|
||||||
|
return in_array(intval($wid), $valid_ws);
|
||||||
|
};
|
||||||
|
if (!$check_membership($w1) || !$check_membership($w2) || !$check_membership($w3)) {
|
||||||
|
echo '<div class="notice notice-error">Einer oder mehrere ausgewählte Workshops gehören nicht zur gewählten Wahl.</div>';
|
||||||
|
} else {
|
||||||
|
$data = [
|
||||||
|
'vorname' => $vorname,
|
||||||
|
'nachname' => $nachname,
|
||||||
|
'wahl_id' => $wahl_id_post,
|
||||||
|
'phase' => $phase_post,
|
||||||
|
'wunsch1' => $w1,
|
||||||
|
'wunsch2' => $w2,
|
||||||
|
'wunsch3' => $w3
|
||||||
|
];
|
||||||
|
if (!empty($_POST['tid'])) {
|
||||||
|
$wpdb->update("{$prefix}kc_teilnehmer", $data, ['id'=>intval($_POST['tid'])]);
|
||||||
|
echo '<div class="notice notice-success">Teilnehmer aktualisiert!</div>';
|
||||||
|
} else {
|
||||||
|
$wpdb->insert("{$prefix}kc_teilnehmer", $data);
|
||||||
|
echo '<div class="notice notice-success">Teilnehmer angelegt!</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teilnehmer bearbeiten
|
||||||
|
if (isset($_GET['edit_teilnehmer'])) {
|
||||||
|
$tid = intval($_GET['edit_teilnehmer']);
|
||||||
|
$tn = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teilnehmer WHERE id=%d", $tid));
|
||||||
|
echo '<div class="kc-admin-table-wrap">';
|
||||||
|
echo '<h2>Teilnehmer bearbeiten</h2>';
|
||||||
|
echo '<form method="post">';
|
||||||
|
echo '<input type="hidden" name="tid" value="'.intval($tn->id).'">';
|
||||||
|
echo '<input type="text" name="vorname" placeholder="Vorname" value="'.esc_attr($tn->vorname).'" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
echo '<input type="text" name="nachname" placeholder="Nachname" value="'.esc_attr($tn->nachname).'" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
|
||||||
|
// Wahl select
|
||||||
|
echo '<label style="display:block;margin:8px 0 4px 0;font-weight:700;">Wahl</label>';
|
||||||
|
echo '<select id="kc-wahl-select" name="wahl_id" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
foreach($all_wahlen as $w) {
|
||||||
|
$selw = (intval($tn->wahl_id) === intval($w->id)) ? ' selected' : '';
|
||||||
|
echo '<option value="'.intval($w->id).'"'.$selw.'>'.esc_html($w->name).'</option>';
|
||||||
|
}
|
||||||
|
echo '</select>';
|
||||||
|
|
||||||
|
// Phase select (fallback content)
|
||||||
|
echo '<label style="display:block;margin:8px 0 4px 0;font-weight:700;">Phase</label>';
|
||||||
|
echo '<select id="kc-phase-select" name="phase" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
$cur_phases = isset($wahl_map[intval($tn->wahl_id)]) ? $wahl_map[intval($tn->wahl_id)]['phases'] : 1;
|
||||||
|
for($i=1;$i<=$cur_phases;$i++){
|
||||||
|
$selp = (intval($tn->phase) === $i) ? ' selected' : '';
|
||||||
|
echo '<option value="'.intval($i).'"'.$selp.'>'.intval($i).'</option>';
|
||||||
|
}
|
||||||
|
echo '</select>';
|
||||||
|
|
||||||
|
// Wunsch selects
|
||||||
|
for ($k=1;$k<=3;$k++){
|
||||||
|
$cur = intval($tn->{'wunsch'.$k});
|
||||||
|
echo '<label style="display:block;margin:8px 0 4px 0;font-weight:700;">Wunsch '.intval($k).'</label>';
|
||||||
|
echo '<select id="kc-wunsch'.intval($k).'" name="wunsch'.intval($k).'" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
echo '<option value="">Bitte Wähle einen Workshop aus</option>';
|
||||||
|
foreach($all_workshops as $ws) {
|
||||||
|
$sel = ($cur === intval($ws->id)) ? ' selected' : '';
|
||||||
|
echo '<option value="'.intval($ws->id).'"'.$sel.'>'.esc_html($ws->name).'</option>';
|
||||||
|
}
|
||||||
|
echo '</select>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<button name="kc_teilnehmer_save" class="kc-btn">Speichern</button>';
|
||||||
|
echo '<a href="?page=kc_teilnehmer" class="kc-btn del" style="margin-left:24px;">Abbrechen</a>';
|
||||||
|
echo '</form>';
|
||||||
|
|
||||||
|
// Provide JS map and init JS: restrict phases/workshops based on Wahl and init Select2
|
||||||
|
echo '<script>var KC_WAHL_MAP = '.json_encode($wahl_map, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP).';</script>';
|
||||||
|
echo '<script>
|
||||||
|
(function(){
|
||||||
|
function fillPhaseOptions(wid){
|
||||||
|
var ph = KC_WAHL_MAP[wid] ? KC_WAHL_MAP[wid].phases : 1;
|
||||||
|
var sel = document.getElementById("kc-phase-select"); if(!sel) return; sel.innerHTML = "";
|
||||||
|
for(var i=1;i<=ph;i++){ var o=document.createElement("option"); o.value=i; o.text=i; sel.appendChild(o); }
|
||||||
|
}
|
||||||
|
function fillWorkshopOptions(wid){
|
||||||
|
var list = KC_WAHL_MAP[wid] ? KC_WAHL_MAP[wid].workshops : [];
|
||||||
|
["kc-wunsch1","kc-wunsch2","kc-wunsch3"].forEach(function(sid){
|
||||||
|
var sel = document.getElementById(sid); if(!sel) return; var cur = sel.value; sel.innerHTML = "";
|
||||||
|
var empty = document.createElement("option"); empty.value = ""; empty.text = "Bitte Wähle einen Workshop aus"; sel.appendChild(empty);
|
||||||
|
list.forEach(function(w){ var o=document.createElement("option"); o.value = w.id; o.text = w.name; sel.appendChild(o); });
|
||||||
|
if(cur) sel.value = cur;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
jQuery(function($){
|
||||||
|
try{ $("#kc-wunsch1,#kc-wunsch2,#kc-wunsch3,#kc-wahl-select,#kc-phase-select").select2({width: "100%"}); }catch(e){}
|
||||||
|
var wsel = document.getElementById("kc-wahl-select"); if(!wsel) return;
|
||||||
|
wsel.addEventListener("change", function(){ fillPhaseOptions(this.value); fillWorkshopOptions(this.value); try{ $("#kc-wunsch1,#kc-wunsch2,#kc-wunsch3,#kc-phase-select").trigger("change.select2"); }catch(e){} });
|
||||||
|
// initial fill
|
||||||
|
fillPhaseOptions(wsel.value); fillWorkshopOptions(wsel.value);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>';
|
||||||
|
echo '</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neuer Teilnehmer anlegen
|
||||||
|
if (isset($_GET['new'])) {
|
||||||
|
echo '<div class="kc-admin-table-wrap">';
|
||||||
|
echo '<h2>Neuen Teilnehmer anlegen</h2>';
|
||||||
|
echo '<form method="post">';
|
||||||
|
echo '<input type="text" name="vorname" placeholder="Vorname" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
echo '<input type="text" name="nachname" placeholder="Nachname" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
|
||||||
|
echo '<label style="display:block;margin:8px 0 4px 0;font-weight:700;">Wahl</label>';
|
||||||
|
echo '<select id="kc-wahl-select" name="wahl_id" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
foreach($all_wahlen as $w) {
|
||||||
|
echo '<option value="'.intval($w->id).'">'.esc_html($w->name).'</option>';
|
||||||
|
}
|
||||||
|
echo '</select>';
|
||||||
|
|
||||||
|
echo '<label style="display:block;margin:8px 0 4px 0;font-weight:700;">Phase</label>';
|
||||||
|
echo '<select id="kc-phase-select" name="phase" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
$first_wahl = reset($all_wahlen);
|
||||||
|
$first_ph = $first_wahl ? max(1,intval($first_wahl->anzahl_einheiten)) : 1;
|
||||||
|
for($i=1;$i<=$first_ph;$i++) echo '<option value="'.intval($i).'">'.intval($i).'</option>';
|
||||||
|
echo '</select>';
|
||||||
|
|
||||||
|
for ($k=1;$k<=3;$k++){
|
||||||
|
echo '<label style="display:block;margin:8px 0 4px 0;font-weight:700;">Wunsch '.intval($k).'</label>';
|
||||||
|
echo '<select id="kc-wunsch'.intval($k).'" name="wunsch'.intval($k).'" required style="margin-bottom:8px;width:100%;padding:7px;">';
|
||||||
|
echo '<option value="">Bitte Wähle einen Workshop aus</option>';
|
||||||
|
foreach($all_workshops as $ws) {
|
||||||
|
echo '<option value="'.intval($ws->id).'">'.esc_html($ws->name).'</option>';
|
||||||
|
}
|
||||||
|
echo '</select>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<button name="kc_teilnehmer_save" class="kc-btn">Speichern</button>';
|
||||||
|
echo '<a href="?page=kc_teilnehmer" class="kc-btn del" style="margin-left:24px;">Abbrechen</a>';
|
||||||
|
echo '</form>';
|
||||||
|
// Init Select2 for nicer selects if available
|
||||||
|
echo '<script>jQuery(function($){try{ $("#kc-wunsch1,#kc-wunsch2,#kc-wunsch3,#kc-wahl-select,#kc-phase-select").select2({width:"100%"}); }catch(e){} });</script>';
|
||||||
|
echo '</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Übersicht
|
||||||
|
// Map für Wahl-ID => Name
|
||||||
|
$wahl_name_map = [];
|
||||||
|
foreach($all_wahlen as $w) {
|
||||||
|
$wahl_name_map[intval($w->id)] = $w->name;
|
||||||
|
}
|
||||||
|
echo '<div class="kc-admin-table-wrap">';
|
||||||
|
echo '<h2 style="margin-top:0;">Alle Teilnehmer</h2>';
|
||||||
|
echo '<a class="kc-btn" style="float:right;margin-bottom:12px;" href="?page=kc_teilnehmer&new=1">+ Neuer Teilnehmer</a>';
|
||||||
|
|
||||||
|
// Wahl-Filter-Buttons sortiert nach KC1, KC2, KC3, dann Rest
|
||||||
|
$kc_buttons = [];
|
||||||
|
$rest_buttons = [];
|
||||||
|
foreach($all_wahlen as $w) {
|
||||||
|
$name = strtoupper($w->name);
|
||||||
|
if ($name === 'KC1' || $name === 'KC2' || $name === 'KC3') {
|
||||||
|
$kc_buttons[$name] = $w;
|
||||||
|
} else {
|
||||||
|
$rest_buttons[] = $w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '<div style="margin:12px 0;clear:both;display:flex;gap:8px;align-items:center;flex-wrap:wrap;">'
|
||||||
|
.'<label style="font-weight:600;">Wahlen filtern:</label>';
|
||||||
|
echo '<button type="button" class="kc-btn kc-wahl-filter-btn" data-wahl-id="" style="padding:6px 10px;">Alle</button>';
|
||||||
|
foreach(["KC1","KC2","KC3"] as $kc) {
|
||||||
|
if(isset($kc_buttons[$kc])) {
|
||||||
|
$w = $kc_buttons[$kc];
|
||||||
|
echo '<button type="button" class="kc-btn kc-wahl-filter-btn" data-wahl-id="'.intval($w->id).'" style="padding:6px 10px;">'.esc_html($w->name).'</button>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($rest_buttons as $w) {
|
||||||
|
echo '<button type="button" class="kc-btn kc-wahl-filter-btn" data-wahl-id="'.intval($w->id).'" style="padding:6px 10px;">'.esc_html($w->name).'</button>';
|
||||||
|
}
|
||||||
|
echo '<span id="kc-wahl-filter-count" style="color:#666;font-size:90%;margin-left:12px;">Alle anzeigen</span>';
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
|
// Platzhalter für Phasen-Filter
|
||||||
|
echo '<div id="kc-phase-filter-row" style="display:none;margin:8px 0 16px 0;gap:8px;align-items:center;flex-wrap:wrap;"></div>';
|
||||||
|
|
||||||
|
// Teilnehmer laden und gruppieren nach Wahl und Phase
|
||||||
|
$teilnehmer = $wpdb->get_results("SELECT * FROM {$prefix}kc_teilnehmer ORDER BY wahl_id, phase, nachname, vorname");
|
||||||
|
$gruppen = [];
|
||||||
|
foreach ($teilnehmer as $tn) {
|
||||||
|
$wid = intval($tn->wahl_id);
|
||||||
|
$ph = intval($tn->phase);
|
||||||
|
$gruppen[$wid][$ph][] = $tn;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($gruppen as $wid => $phasen) {
|
||||||
|
$wahl_disp = isset($wahl_name_map[$wid]) ? esc_html($wahl_name_map[$wid]) : $wid;
|
||||||
|
// Gesamtanzahl Teilnehmer für diese Wahl berechnen
|
||||||
|
$gesamt = 0;
|
||||||
|
foreach ($phasen as $tns) $gesamt += count($tns);
|
||||||
|
echo '<details open style="margin:10px 0 18px 0;border:1px solid #eaeaea;border-radius:6px;padding:8px;">';
|
||||||
|
echo '<summary style="font-weight:700;cursor:pointer;">'. $wahl_disp . ' <span style="color:#555;font-weight:600;">(' . $gesamt . ' TN)</span></summary>';
|
||||||
|
foreach ($phasen as $phase => $tns) {
|
||||||
|
echo '<details open style="margin:10px 0 10px 0;border:1px solid #f0f0f0;border-radius:6px;padding:8px;">';
|
||||||
|
echo '<summary style="font-weight:600;">Phase '.intval($phase).' <span style="color:#555;font-weight:600;">('.count($tns).' TN)</span></summary>';
|
||||||
|
echo '<table class="kc-admin-table" style="margin:8px 0;">';
|
||||||
|
echo '<thead><tr><th>Vorname</th><th>Nachname</th><th>Wahl</th><th>Phase</th><th>Wunsch 1</th><th>Wunsch 2</th><th>Wunsch 3</th><th>Aktion</th></tr></thead><tbody>';
|
||||||
|
foreach ($tns as $tn) {
|
||||||
|
$w1_id = intval($tn->wunsch1);
|
||||||
|
$w2_id = intval($tn->wunsch2);
|
||||||
|
$w3_id = intval($tn->wunsch3);
|
||||||
|
$w1_disp = $w1_id && isset($workshops_map[$w1_id]) ? esc_html($workshops_map[$w1_id]) : ($w1_id ? intval($w1_id) : '<em style="color:#999;">Keine</em>');
|
||||||
|
$w2_disp = $w2_id && isset($workshops_map[$w2_id]) ? esc_html($workshops_map[$w2_id]) : ($w2_id ? intval($w2_id) : '<em style="color:#999;">Keine</em>');
|
||||||
|
$w3_disp = $w3_id && isset($workshops_map[$w3_id]) ? esc_html($workshops_map[$w3_id]) : ($w3_id ? intval($w3_id) : '<em style="color:#999;">Keine</em>');
|
||||||
|
$wahl_disp = isset($wahl_name_map[intval($tn->wahl_id)]) ? esc_html($wahl_name_map[intval($tn->wahl_id)]) : intval($tn->wahl_id);
|
||||||
|
echo "<tr data-wahl-id='".intval($tn->wahl_id)."'>
|
||||||
|
<td>".esc_html($tn->vorname)."</td>
|
||||||
|
<td>".esc_html($tn->nachname)."</td>
|
||||||
|
<td>".$wahl_disp."</td>
|
||||||
|
<td>".intval($tn->phase)."</td>
|
||||||
|
<td>".$w1_disp."</td>
|
||||||
|
<td>".$w2_disp."</td>
|
||||||
|
<td>".$w3_disp."</td>
|
||||||
|
<td class='kc-actions'>
|
||||||
|
<a class='kc-btn edit' href='?page=kc_teilnehmer&edit_teilnehmer={$tn->id}'>Bearbeiten</a>
|
||||||
|
<a class='kc-btn del' href='?page=kc_teilnehmer&delete_teilnehmer={$tn->id}' onclick=\"return confirm('Wirklich loeschen?');\">Loeschen</a>
|
||||||
|
</td>
|
||||||
|
</tr>";
|
||||||
|
}
|
||||||
|
echo '</tbody></table>';
|
||||||
|
echo '</details>';
|
||||||
|
}
|
||||||
|
echo '</details>';
|
||||||
|
}
|
||||||
|
// JS für Wahl- und Phasen-Filter
|
||||||
|
echo '<style>.kc-wahl-filter-btn.active{background:#4CAF50;color:#fff;} .kc-phase-filter-btn.active{background:#1976d2;color:#fff;}</style>';
|
||||||
|
echo '<script>
|
||||||
|
(function() {
|
||||||
|
var btns = Array.prototype.slice.call(document.querySelectorAll(".kc-wahl-filter-btn"));
|
||||||
|
var rows = Array.prototype.slice.call(document.querySelectorAll(".kc-admin-table tbody tr"));
|
||||||
|
var status = document.getElementById("kc-wahl-filter-count");
|
||||||
|
var phaseRow = document.getElementById("kc-phase-filter-row");
|
||||||
|
// Wahl-Map für Phasen
|
||||||
|
var wahlMap = '.json_encode($wahl_map, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP).';
|
||||||
|
var currentWahl = "";
|
||||||
|
var currentPhase = "";
|
||||||
|
|
||||||
|
function renderPhaseButtons(wahlId) {
|
||||||
|
phaseRow.innerHTML = "";
|
||||||
|
if (!wahlId || !wahlMap[wahlId]) { phaseRow.style.display = "none"; currentPhase = ""; return; }
|
||||||
|
var phases = wahlMap[wahlId].phases || 1;
|
||||||
|
var label = document.createElement("label");
|
||||||
|
label.textContent = "Phasen filtern:";
|
||||||
|
label.style.fontWeight = "600";
|
||||||
|
label.style.marginRight = "8px";
|
||||||
|
phaseRow.appendChild(label);
|
||||||
|
var allBtn = document.createElement("button");
|
||||||
|
allBtn.type = "button";
|
||||||
|
allBtn.className = "kc-btn kc-phase-filter-btn active";
|
||||||
|
allBtn.setAttribute("data-phase", "");
|
||||||
|
allBtn.style.padding = "6px 10px";
|
||||||
|
allBtn.textContent = "Alle";
|
||||||
|
phaseRow.appendChild(allBtn);
|
||||||
|
for(var i=1;i<=phases;i++){
|
||||||
|
var btn = document.createElement("button");
|
||||||
|
btn.type = "button";
|
||||||
|
btn.className = "kc-btn kc-phase-filter-btn";
|
||||||
|
btn.setAttribute("data-phase", i);
|
||||||
|
btn.style.padding = "6px 10px";
|
||||||
|
btn.textContent = i;
|
||||||
|
phaseRow.appendChild(btn);
|
||||||
|
}
|
||||||
|
phaseRow.style.display = "flex";
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilter(wahlId, phase) {
|
||||||
|
var shown = 0;
|
||||||
|
rows.forEach(function(row) {
|
||||||
|
var rid = row.getAttribute("data-wahl-id");
|
||||||
|
var ph = row.querySelector("td:nth-child(4)").textContent.trim();
|
||||||
|
var show = false;
|
||||||
|
if (!wahlId) {
|
||||||
|
show = true;
|
||||||
|
} else if (!phase) {
|
||||||
|
show = (rid == wahlId);
|
||||||
|
} else {
|
||||||
|
show = (rid == wahlId && ph == phase);
|
||||||
|
}
|
||||||
|
row.style.display = show ? "" : "none";
|
||||||
|
if (show) shown++;
|
||||||
|
});
|
||||||
|
if (status) status.textContent = (wahlId ? (shown+" angezeigt") : "Alle anzeigen");
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachPhaseEvents() {
|
||||||
|
var phaseBtns = Array.prototype.slice.call(document.querySelectorAll(".kc-phase-filter-btn"));
|
||||||
|
phaseBtns.forEach(function(btn) {
|
||||||
|
btn.addEventListener("click", function() {
|
||||||
|
phaseBtns.forEach(function(b){b.classList.remove("active");});
|
||||||
|
btn.classList.add("active");
|
||||||
|
currentPhase = btn.getAttribute("data-phase");
|
||||||
|
applyFilter(currentWahl, currentPhase);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
btns.forEach(function(btn) {
|
||||||
|
btn.addEventListener("click", function() {
|
||||||
|
btns.forEach(function(b){b.classList.remove("active");});
|
||||||
|
btn.classList.add("active");
|
||||||
|
var wahlId = btn.getAttribute("data-wahl-id");
|
||||||
|
currentWahl = wahlId;
|
||||||
|
currentPhase = "";
|
||||||
|
renderPhaseButtons(wahlId);
|
||||||
|
applyFilter(wahlId, "");
|
||||||
|
attachPhaseEvents();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Default: Alle aktiv
|
||||||
|
if(btns.length) btns[0].classList.add("active");
|
||||||
|
renderPhaseButtons("");
|
||||||
|
applyFilter("", "");
|
||||||
|
})();
|
||||||
|
</script>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
487
includes/admin-zuteilungen.php
Normal file
487
includes/admin-zuteilungen.php
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
<?php
|
||||||
|
// --- CSV Export Handler: Muss GANZ AN DEN ANFANG! ---
|
||||||
|
if (isset($_GET['export_csv']) && current_user_can('manage_options')) {
|
||||||
|
$wahl_id = intval($_GET['export_csv']);
|
||||||
|
global $wpdb;
|
||||||
|
$prefix = $wpdb->prefix;
|
||||||
|
$wahl = $wpdb->get_row("SELECT * FROM {$prefix}kc_wahlen WHERE id={$wahl_id}");
|
||||||
|
if (!$wahl) exit('Wahl nicht gefunden');
|
||||||
|
|
||||||
|
// Workshops für diese Wahl holen
|
||||||
|
$workshops = $wpdb->get_results(
|
||||||
|
"SELECT ws.id, ws.name FROM {$prefix}kc_workshops ws JOIN {$prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id WHERE ww.wahl_id = ".intval($wahl_id)
|
||||||
|
);
|
||||||
|
$ws_names = [];
|
||||||
|
foreach($workshops as $ws) $ws_names[$ws->id] = $ws->name;
|
||||||
|
|
||||||
|
// Zuteilungen holen
|
||||||
|
$rows = $wpdb->get_results("SELECT * FROM {$prefix}kc_zuteilung WHERE wahl_id=".intval($wahl_id));
|
||||||
|
|
||||||
|
// Phasen bestimmen
|
||||||
|
$phases = [];
|
||||||
|
foreach($rows as $row) {
|
||||||
|
if ($row->phase === null || $row->phase === '') continue;
|
||||||
|
$phases[intval($row->phase)] = true;
|
||||||
|
}
|
||||||
|
$phases = array_keys($phases);
|
||||||
|
sort($phases, SORT_NUMERIC);
|
||||||
|
|
||||||
|
// Teamer pro Workshop/Phase (wie frontend-ergebnis)
|
||||||
|
$ws_teamers = [];
|
||||||
|
$ws_ids = array_keys($ws_names);
|
||||||
|
if (!empty($ws_ids)) {
|
||||||
|
foreach($ws_ids as $ws_id) {
|
||||||
|
foreach($phases as $phase) {
|
||||||
|
$trows = $wpdb->get_results($wpdb->prepare(
|
||||||
|
"SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt ".
|
||||||
|
"JOIN {$prefix}kc_teamer t ON wt.teamer_id = t.id ".
|
||||||
|
"WHERE wt.workshop_id = %d AND wt.wahl_id = %d AND wt.phase = %d",
|
||||||
|
$ws_id, $wahl_id, $phase
|
||||||
|
));
|
||||||
|
if (empty($trows)) {
|
||||||
|
$trows = $wpdb->get_results($wpdb->prepare(
|
||||||
|
"SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt ".
|
||||||
|
"JOIN {$prefix}kc_teamer t ON wt.teamer_id = t.id ".
|
||||||
|
"WHERE wt.workshop_id = %d AND wt.wahl_id = %d AND wt.phase IS NULL",
|
||||||
|
$ws_id, $wahl_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (empty($trows)) {
|
||||||
|
$trows = $wpdb->get_results($wpdb->prepare(
|
||||||
|
"SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt ".
|
||||||
|
"JOIN {$prefix}kc_teamer t ON wt.teamer_id = t.id ".
|
||||||
|
"WHERE wt.workshop_id = %d AND wt.wahl_id IS NULL AND wt.phase IS NULL",
|
||||||
|
$ws_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (!empty($trows)) {
|
||||||
|
$key = intval($ws_id) . '_' . intval($phase);
|
||||||
|
$ws_teamers[$key] = [];
|
||||||
|
foreach ($trows as $tr) {
|
||||||
|
$ws_teamers[$key][] = trim($tr->vorname.' '.$tr->nachname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppieren und sortieren wie im Frontend: erst nach Phase, dann Workshop, dann Teilnehmer
|
||||||
|
$workshop_groups = [];
|
||||||
|
$phases = [];
|
||||||
|
foreach($rows as $row) {
|
||||||
|
if ($row->phase === null || $row->phase === '') continue;
|
||||||
|
$phaseNum = intval($row->phase);
|
||||||
|
$phases[$phaseNum] = true;
|
||||||
|
if ($row->workshop_id && isset($ws_names[$row->workshop_id])) {
|
||||||
|
$workshop_groups[$phaseNum][$row->workshop_id][] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$phases = array_keys($phases);
|
||||||
|
sort($phases, SORT_NUMERIC);
|
||||||
|
|
||||||
|
header('Content-Type: text/csv; charset=utf-8');
|
||||||
|
header('Content-Disposition: attachment; filename="kc_zuteilung_wahl_'.$wahl_id.'.csv"');
|
||||||
|
// Schreibe UTF-8 BOM, damit Excel Umlaute korrekt erkennt
|
||||||
|
echo "\xEF\xBB\xBF";
|
||||||
|
$output = fopen('php://output', 'w');
|
||||||
|
// Excel erwartet in DE meist ; als Trennzeichen
|
||||||
|
$delimiter = ';';
|
||||||
|
fputcsv($output, ['Phase','Workshop','Teamer','Teilnehmer'], $delimiter);
|
||||||
|
foreach($phases as $phase) {
|
||||||
|
if (empty($workshop_groups[$phase])) continue;
|
||||||
|
$display = [];
|
||||||
|
foreach($ws_names as $ws_id => $ws_name) {
|
||||||
|
$teilnehmer = isset($workshop_groups[$phase][$ws_id]) ? $workshop_groups[$phase][$ws_id] : [];
|
||||||
|
$count = count($teilnehmer);
|
||||||
|
if ($count === 0) continue;
|
||||||
|
$display[] = [
|
||||||
|
'id' => $ws_id,
|
||||||
|
'name' => $ws_name,
|
||||||
|
'teilnehmer' => $teilnehmer,
|
||||||
|
'count' => $count
|
||||||
|
];
|
||||||
|
}
|
||||||
|
usort($display, function($a, $b) { return $a['count'] - $b['count']; });
|
||||||
|
foreach($display as $d) {
|
||||||
|
$ws_id = $d['id'];
|
||||||
|
$ws_name = $d['name'];
|
||||||
|
$teilnehmer = $d['teilnehmer'];
|
||||||
|
$teamer_key = intval($ws_id) . '_' . intval($phase);
|
||||||
|
$teamer_str = !empty($ws_teamers[$teamer_key]) ? implode(', ', $ws_teamers[$teamer_key]) : '';
|
||||||
|
usort($teilnehmer, function($a, $b) {
|
||||||
|
return strcmp($a->nachname . $a->vorname, $b->nachname . $b->vorname);
|
||||||
|
});
|
||||||
|
foreach($teilnehmer as $t) {
|
||||||
|
$vorname = preg_replace('/<[^>]*>/', '', $t->vorname);
|
||||||
|
$nachname = preg_replace('/<[^>]*>/', '', $t->nachname);
|
||||||
|
$teilnehmer_name = trim($vorname . ', ' . $nachname);
|
||||||
|
$ws_name_clean = preg_replace('/<[^>]*>/', '', $ws_name);
|
||||||
|
$teamer_str_clean = preg_replace('/<[^>]*>/', '', $teamer_str);
|
||||||
|
fputcsv($output, [
|
||||||
|
$phase,
|
||||||
|
$ws_name_clean,
|
||||||
|
$teamer_str_clean,
|
||||||
|
$teilnehmer_name,
|
||||||
|
$wunsch
|
||||||
|
], $delimiter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($output);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
function kc_zeige_zuteilung($wahl_id) {
|
||||||
|
global $wpdb;
|
||||||
|
$prefix = $wpdb->prefix;
|
||||||
|
$wahl_id = intval($wahl_id);
|
||||||
|
$wahl = $wpdb->get_row("SELECT * FROM {$prefix}kc_wahlen WHERE id={$wahl_id}");
|
||||||
|
if (!$wahl) return;
|
||||||
|
|
||||||
|
// Workshops dieser Wahl holen
|
||||||
|
$workshops = $wpdb->get_results(
|
||||||
|
"SELECT ws.id, ws.name
|
||||||
|
FROM {$prefix}kc_workshops ws
|
||||||
|
JOIN {$prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id
|
||||||
|
WHERE ww.wahl_id = " . $wahl_id
|
||||||
|
);
|
||||||
|
$ws_names = [];
|
||||||
|
foreach($workshops as $ws) $ws_names[$ws->id] = $ws->name;
|
||||||
|
|
||||||
|
// Zuteilungen holen
|
||||||
|
$rows = $wpdb->get_results(
|
||||||
|
"SELECT * FROM {$prefix}kc_zuteilung WHERE wahl_id=" . $wahl_id
|
||||||
|
);
|
||||||
|
|
||||||
|
$workshop_groups = [];
|
||||||
|
$nicht_zugeteilt = [];
|
||||||
|
foreach($rows as $row) {
|
||||||
|
if ($row->workshop_id && isset($ws_names[$row->workshop_id])) {
|
||||||
|
$workshop_groups[$row->workshop_id][] = $row;
|
||||||
|
} else {
|
||||||
|
$nicht_zugeteilt[] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uasort($workshop_groups, function($a, $b) {
|
||||||
|
return count($a) - count($b);
|
||||||
|
});
|
||||||
|
|
||||||
|
echo '<div class="kc-admin-table-wrap">';
|
||||||
|
echo '<h2 style="margin-top:0;">Zuteilung: '.esc_html($wahl->name).'</h2>';
|
||||||
|
|
||||||
|
// Anzahl Phasen der Wahl
|
||||||
|
$phasen = intval($wahl->anzahl_einheiten);
|
||||||
|
if ($phasen < 1) $phasen = 1;
|
||||||
|
|
||||||
|
// Für jede Phase eine einklappbare Sektion
|
||||||
|
for ($phase = 1; $phase <= $phasen; $phase++) {
|
||||||
|
echo '<details class="kc-phase-details" open>';
|
||||||
|
echo '<summary>Phase '.intval($phase).' <span class="kc-count">(' . intval(count(array_filter($rows, function($r) use ($phase){ return intval($r->phase) === $phase; }))) . ' TN)</span></summary>';
|
||||||
|
|
||||||
|
// Innerhalb der Phase: zeige pro Workshop die Teilnehmer (falls vorhanden)
|
||||||
|
foreach ($ws_names as $ws_id => $ws_name) {
|
||||||
|
// Filtere Teilnehmer dieser Phase & dieses Workshops
|
||||||
|
$filtered = array_filter($rows, function($r) use ($phase, $ws_id) {
|
||||||
|
return intval($r->phase) === $phase && intval($r->workshop_id) === intval($ws_id);
|
||||||
|
});
|
||||||
|
if (empty($filtered)) continue;
|
||||||
|
|
||||||
|
echo '<div class="kc-workshop-card">';
|
||||||
|
echo '<b>'.esc_html($ws_name).'</b> <span class="kc-count">(' . count($filtered) . ' TN)</span><br>';
|
||||||
|
echo '<table style="width:100%;margin:8px 0">';
|
||||||
|
echo '<tr><th>Name</th><th>Wunsch</th><th>Workshop</th></tr>';
|
||||||
|
foreach ($filtered as $t) {
|
||||||
|
if ($t->wunsch_rang == 0) {
|
||||||
|
$wunsch = "Vorzuteilung";
|
||||||
|
} elseif ($t->wunsch_rang == -1) {
|
||||||
|
$wunsch = "zugelost";
|
||||||
|
} elseif ($t->wunsch_rang == 99) {
|
||||||
|
$wunsch = "Zulosung";
|
||||||
|
} elseif ($t->wunsch_rang > 0) {
|
||||||
|
$wunsch = intval($t->wunsch_rang) . '.';
|
||||||
|
} else {
|
||||||
|
$wunsch = '';
|
||||||
|
}
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<td>'.esc_html($t->vorname.' '.$t->nachname).'</td>';
|
||||||
|
echo '<td>'.$wunsch.'</td>';
|
||||||
|
echo '<td>'.esc_html($ws_name).'</td>';
|
||||||
|
echo '</tr>';
|
||||||
|
}
|
||||||
|
echo '</table></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teilnehmer dieser Phase, die keinem Workshop zugeordnet sind
|
||||||
|
$unassigned_phase = array_filter($rows, function($r) use ($phase) { return intval($r->phase) === $phase && (empty($r->workshop_id) || !intval($r->workshop_id)); });
|
||||||
|
if (!empty($unassigned_phase)) {
|
||||||
|
echo '<div class="kc-unassigned">';
|
||||||
|
echo '<b>Nicht zugeteilt (Phase '.intval($phase).'):</b><br><ul style="margin:6px 0 0 16px;">';
|
||||||
|
foreach($unassigned_phase as $t) {
|
||||||
|
echo '<li>'.esc_html($t->vorname.' '.$t->nachname).'</li>';
|
||||||
|
}
|
||||||
|
echo '</ul></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</details>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($nicht_zugeteilt)) {
|
||||||
|
echo '<div style="background:#fee;padding:14px;margin:14px 0;border-radius:10px;box-shadow:0 1px 5px #b6d33321;">';
|
||||||
|
echo '<b>Nicht zugeteilt:</b><br><ul style="margin:0 0 0 15px;">';
|
||||||
|
foreach($nicht_zugeteilt as $t) {
|
||||||
|
echo '<li>'.esc_html($t->vorname.' '.$t->nachname).' (Phase '.intval($t->phase).')</li>';
|
||||||
|
}
|
||||||
|
echo '</ul></div>';
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function kc_zuteilungen_page() {
|
||||||
|
global $wpdb;
|
||||||
|
$prefix = $wpdb->prefix;
|
||||||
|
kc_admin_tabs('kc_zuteilungen');
|
||||||
|
|
||||||
|
// Aktionen: Zuteilung ausführen oder löschen (per Wahl)
|
||||||
|
if (isset($_GET['run_zuteilung'])) {
|
||||||
|
$run_id = intval($_GET['run_zuteilung']);
|
||||||
|
if ($run_id) {
|
||||||
|
// Delegiere an die Zuteilungslogik
|
||||||
|
if (function_exists('kc_run_zuteilung')) {
|
||||||
|
kc_run_zuteilung($run_id);
|
||||||
|
echo '<div class="notice notice-success">Zuteilung für Wahl ID '.intval($run_id).' ausgeführt.</div>';
|
||||||
|
echo "<meta http-equiv='refresh' content='1;url=".esc_url(admin_url('admin.php?page=kc_zuteilungen'))."'>";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
echo '<div class="notice notice-error">Die Zuteilungsfunktion ist nicht verfügbar.</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['delete_zuteilung'])) {
|
||||||
|
if ($del_id) {
|
||||||
|
$wpdb->delete("{$prefix}kc_zuteilung", ['wahl_id' => $del_id]);
|
||||||
|
echo '<div class="notice notice-success">Zuteilungen für Wahl ID '.intval($del_id).' wurden gelöscht.</div>';
|
||||||
|
echo "<meta http-equiv='refresh' content='1;url=".esc_url(admin_url('admin.php?page=kc_zuteilungen'))."'>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Übersicht: Zeige Zuteilungen für ALLE Wahlen
|
||||||
|
echo '<div class="kc-admin-table-wrap">';
|
||||||
|
echo '<h2 style="margin-top:0;">Alle Zuteilungen</h2>';
|
||||||
|
$wahlen = $wpdb->get_results("SELECT * FROM {$prefix}kc_wahlen WHERE deleted=0 ORDER BY id DESC");
|
||||||
|
foreach($wahlen as $wahl) {
|
||||||
|
$run_url = add_query_arg('run_zuteilung', $wahl->id, admin_url('admin.php?page=kc_zuteilungen'));
|
||||||
|
$del_url = add_query_arg('delete_zuteilung', $wahl->id, admin_url('admin.php?page=kc_zuteilungen'));
|
||||||
|
$details_url = add_query_arg('show_zuteilung', $wahl->id, admin_url('admin.php?page=kc_wahlen'));
|
||||||
|
$csv_url = add_query_arg(['export_csv' => $wahl->id], admin_url('admin.php?page=kc_zuteilungen'));
|
||||||
|
// Workshops & Zuteilungen für diese Wahl vorbereiten
|
||||||
|
$workshops = $wpdb->get_results(
|
||||||
|
"SELECT ws.id, ws.name
|
||||||
|
FROM {$prefix}kc_workshops ws
|
||||||
|
JOIN {$prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id
|
||||||
|
WHERE ww.wahl_id = ".intval($wahl->id)
|
||||||
|
);
|
||||||
|
$ws_names = [];
|
||||||
|
foreach($workshops as $ws) $ws_names[$ws->id] = $ws->name;
|
||||||
|
|
||||||
|
// Zuteilungen holen
|
||||||
|
$rows = $wpdb->get_results(
|
||||||
|
"SELECT * FROM {$prefix}kc_zuteilung WHERE wahl_id=".intval($wahl->id)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Gesamt-Details pro Wahl: einklappbar
|
||||||
|
echo '<details style="margin-top:18px;border:1px solid #eaeaea;border-radius:6px;padding:8px;">';
|
||||||
|
echo '<summary style="font-weight:700;cursor:pointer;">'.esc_html($wahl->name).' <span style="color:#555;font-weight:600;">('.count($rows).' TN)</span>';
|
||||||
|
echo ' <span style="float:right">';
|
||||||
|
echo '<a class="kc-btn" href="'.esc_url($details_url).'">Details</a> ';
|
||||||
|
echo '<a class="kc-btn" href="'.esc_url($run_url).'">Zuteilung ausführen</a> ';
|
||||||
|
echo '<a class="kc-btn del" href="'.esc_url($del_url).'" onclick="return confirm(\'Alle Zuteilungen für diese Wahl löschen?\');">Zuteilungen löschen</a> ';
|
||||||
|
echo '<a class="kc-btn" style="background:#2da66a;color:#fff;" href="'.esc_url($csv_url).'">CSV Export</a>';
|
||||||
|
echo '</span>';
|
||||||
|
echo '</summary>';
|
||||||
|
// --- CSV Export Handler ---
|
||||||
|
if (isset($_GET['export_csv']) && current_user_can('manage_options')) {
|
||||||
|
$wahl_id = intval($_GET['export_csv']);
|
||||||
|
global $wpdb;
|
||||||
|
$prefix = $wpdb->prefix;
|
||||||
|
$wahl = $wpdb->get_row("SELECT * FROM {$prefix}kc_wahlen WHERE id={$wahl_id}");
|
||||||
|
if (!$wahl) exit('Wahl nicht gefunden');
|
||||||
|
|
||||||
|
// Workshops für diese Wahl holen
|
||||||
|
$workshops = $wpdb->get_results(
|
||||||
|
"SELECT ws.id, ws.name FROM {$prefix}kc_workshops ws JOIN {$prefix}kc_wahl_workshops ww ON ws.id = ww.workshop_id WHERE ww.wahl_id = ".intval($wahl_id)
|
||||||
|
);
|
||||||
|
$ws_names = [];
|
||||||
|
foreach($workshops as $ws) $ws_names[$ws->id] = $ws->name;
|
||||||
|
|
||||||
|
// Zuteilungen holen
|
||||||
|
$rows = $wpdb->get_results("SELECT * FROM {$prefix}kc_zuteilung WHERE wahl_id=".intval($wahl_id));
|
||||||
|
|
||||||
|
// Phasen bestimmen
|
||||||
|
$phases = [];
|
||||||
|
foreach($rows as $row) {
|
||||||
|
if ($row->phase === null || $row->phase === '') continue;
|
||||||
|
$phases[intval($row->phase)] = true;
|
||||||
|
}
|
||||||
|
$phases = array_keys($phases);
|
||||||
|
sort($phases, SORT_NUMERIC);
|
||||||
|
|
||||||
|
// CSV Header
|
||||||
|
header('Content-Type: text/csv; charset=utf-8');
|
||||||
|
header('Content-Disposition: attachment; filename="kc_zuteilung_wahl_'.$wahl_id.'.csv"');
|
||||||
|
$output = fopen('php://output', 'w');
|
||||||
|
// Kopfzeile
|
||||||
|
fputcsv($output, ['Phase','Workshop','Teamer','Teilnehmer Vorname','Teilnehmer Nachname']);
|
||||||
|
|
||||||
|
// Teamer pro Workshop/Phase (wie frontend-ergebnis)
|
||||||
|
$ws_teamers = [];
|
||||||
|
$ws_ids = array_keys($ws_names);
|
||||||
|
if (!empty($ws_ids)) {
|
||||||
|
foreach($ws_ids as $ws_id) {
|
||||||
|
foreach($phases as $phase) {
|
||||||
|
$trows = $wpdb->get_results($wpdb->prepare(
|
||||||
|
"SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt ".
|
||||||
|
"JOIN {$prefix}kc_teamer t ON wt.teamer_id = t.id ".
|
||||||
|
"WHERE wt.workshop_id = %d AND wt.wahl_id = %d AND wt.phase = %d",
|
||||||
|
$ws_id, $wahl_id, $phase
|
||||||
|
));
|
||||||
|
if (empty($trows)) {
|
||||||
|
$trows = $wpdb->get_results($wpdb->prepare(
|
||||||
|
"SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt ".
|
||||||
|
"JOIN {$prefix}kc_teamer t ON wt.teamer_id = t.id ".
|
||||||
|
"WHERE wt.workshop_id = %d AND wt.wahl_id = %d AND wt.phase IS NULL",
|
||||||
|
$ws_id, $wahl_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (empty($trows)) {
|
||||||
|
$trows = $wpdb->get_results($wpdb->prepare(
|
||||||
|
"SELECT t.vorname, t.nachname FROM {$prefix}kc_workshop_teamer wt ".
|
||||||
|
"JOIN {$prefix}kc_teamer t ON wt.teamer_id = t.id ".
|
||||||
|
"WHERE wt.workshop_id = %d AND wt.wahl_id IS NULL AND wt.phase IS NULL",
|
||||||
|
$ws_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (!empty($trows)) {
|
||||||
|
$key = intval($ws_id) . '_' . intval($phase);
|
||||||
|
$ws_teamers[$key] = [];
|
||||||
|
foreach ($trows as $tr) {
|
||||||
|
$ws_teamers[$key][] = trim($tr->vorname.' '.$tr->nachname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gruppieren und sortieren wie im Frontend: erst nach Phase, dann Workshop, dann Teilnehmer
|
||||||
|
// 1. Gruppieren nach Phase und Workshop
|
||||||
|
$workshop_groups = [];
|
||||||
|
$phases = [];
|
||||||
|
foreach($rows as $row) {
|
||||||
|
if ($row->phase === null || $row->phase === '') continue;
|
||||||
|
$phaseNum = intval($row->phase);
|
||||||
|
$phases[$phaseNum] = true;
|
||||||
|
if ($row->workshop_id && isset($ws_names[$row->workshop_id])) {
|
||||||
|
$workshop_groups[$phaseNum][$row->workshop_id][] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$phases = array_keys($phases);
|
||||||
|
sort($phases, SORT_NUMERIC);
|
||||||
|
// 2. Pro Phase, pro Workshop (nur mit Teilnehmern), sortiert nach Teilnehmerzahl aufsteigend
|
||||||
|
foreach($phases as $phase) {
|
||||||
|
if (empty($workshop_groups[$phase])) continue;
|
||||||
|
// Workshops mit Teilnehmern in dieser Phase
|
||||||
|
$display = [];
|
||||||
|
foreach($ws_names as $ws_id => $ws_name) {
|
||||||
|
$teilnehmer = isset($workshop_groups[$phase][$ws_id]) ? $workshop_groups[$phase][$ws_id] : [];
|
||||||
|
$count = count($teilnehmer);
|
||||||
|
if ($count === 0) continue;
|
||||||
|
$display[] = [
|
||||||
|
'id' => $ws_id,
|
||||||
|
'name' => $ws_name,
|
||||||
|
'teilnehmer' => $teilnehmer,
|
||||||
|
'count' => $count
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// Sortieren nach Teilnehmerzahl aufsteigend
|
||||||
|
usort($display, function($a, $b) { return $a['count'] - $b['count']; });
|
||||||
|
foreach($display as $d) {
|
||||||
|
$ws_id = $d['id'];
|
||||||
|
$ws_name = $d['name'];
|
||||||
|
$teilnehmer = $d['teilnehmer'];
|
||||||
|
$teamer_key = intval($ws_id) . '_' . intval($phase);
|
||||||
|
$teamer_str = !empty($ws_teamers[$teamer_key]) ? implode(', ', $ws_teamers[$teamer_key]) : '';
|
||||||
|
// Teilnehmer sortieren (optional: nach Name)
|
||||||
|
usort($teilnehmer, function($a, $b) {
|
||||||
|
return strcmp($a->nachname . $a->vorname, $b->nachname . $b->vorname);
|
||||||
|
});
|
||||||
|
foreach($teilnehmer as $t) {
|
||||||
|
$vorname = preg_replace('/<[^>]*>/', '', $t->vorname);
|
||||||
|
$nachname = preg_replace('/<[^>]*>/', '', $t->nachname);
|
||||||
|
$ws_name_clean = preg_replace('/<[^>]*>/', '', $ws_name);
|
||||||
|
$teamer_str_clean = preg_replace('/<[^>]*>/', '', $teamer_str);
|
||||||
|
$wunsch = $t->wunsch_rang == 0 ? "Vorzuteilung" : ($t->wunsch_rang > 0 ? intval($t->wunsch_rang).'.' : ($t->wunsch_rang==-1?"zugelost":""));
|
||||||
|
$zuteilung = $t->wunsch_rang == 0 ? 'Vorzuteilung' : ($t->wunsch_rang==-1?'Zulosung':'Wunsch');
|
||||||
|
fputcsv($output, [
|
||||||
|
$phase,
|
||||||
|
$ws_name_clean,
|
||||||
|
$teamer_str_clean,
|
||||||
|
$vorname,
|
||||||
|
$nachname,
|
||||||
|
$wunsch,
|
||||||
|
$zuteilung
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($output);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anzahl Phasen der Wahl
|
||||||
|
$phasen = intval($wahl->anzahl_einheiten);
|
||||||
|
if ($phasen < 1) $phasen = 1;
|
||||||
|
|
||||||
|
for ($phase = 1; $phase <= $phasen; $phase++) {
|
||||||
|
echo '<details open style="margin:10px 0;padding:8px;border:1px solid #f0f0f0;border-radius:6px;">';
|
||||||
|
echo '<summary style="font-weight:600;">Phase '.intval($phase).' <span style="color:#555;font-weight:600;">(' . intval(count(array_filter($rows, function($r) use ($phase){ return intval($r->phase) === $phase; }))) . ' TN)</span></summary>';
|
||||||
|
|
||||||
|
// Für jede Workshop zeigen, falls Teilnehmer in dieser Phase zugeordnet sind
|
||||||
|
foreach ($ws_names as $ws_id => $ws_name) {
|
||||||
|
$filtered = array_filter($rows, function($r) use ($phase, $ws_id) {
|
||||||
|
return intval($r->phase) === $phase && intval($r->workshop_id) === intval($ws_id);
|
||||||
|
});
|
||||||
|
if (empty($filtered)) continue;
|
||||||
|
echo '<div style="background:#f9f9f9;margin:8px 0;padding:10px;border-radius:8px;">';
|
||||||
|
echo '<b>'.esc_html($ws_name).'</b> <span style="color:#555;font-size:90%">(' . count($filtered) . ' TN)</span><br>';
|
||||||
|
echo '<table style="width:100%;margin:8px 0">';
|
||||||
|
echo '<tr><th>Name</th><th>Wunsch</th><th>Workshop</th></tr>';
|
||||||
|
foreach ($filtered as $t) {
|
||||||
|
$wunsch = $t->wunsch_rang == 0 ? "Vorzuteilung" : ($t->wunsch_rang > 0 ? intval($t->wunsch_rang).'.' : ($t->wunsch_rang==-1?"zugelost":""));
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<td>'.esc_html($t->vorname.' '.$t->nachname).'</td>';
|
||||||
|
echo '<td>'.$wunsch.'</td>';
|
||||||
|
echo '<td>'.esc_html($ws_name).'</td>';
|
||||||
|
echo '</tr>';
|
||||||
|
}
|
||||||
|
echo '</table></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teilnehmer dieser Phase ohne Workshop
|
||||||
|
$unassigned_phase = array_filter($rows, function($r) use ($phase) { return intval($r->phase) === $phase && (empty($r->workshop_id) || !intval($r->workshop_id)); });
|
||||||
|
if (!empty($unassigned_phase)) {
|
||||||
|
echo '<div style="background:#fee;padding:10px;margin-top:8px;border-radius:8px;">';
|
||||||
|
echo '<b>Nicht zugeteilt (Phase '.intval($phase).'):</b><br><ul style="margin:6px 0 0 16px;">';
|
||||||
|
foreach($unassigned_phase as $t) {
|
||||||
|
echo '<li>'.esc_html($t->vorname.' '.$t->nachname).'</li>';
|
||||||
|
}
|
||||||
|
echo '</ul></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</details>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</details>';
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user