Compare commits

..

12 Commits

Author SHA1 Message Date
rxf
f6e9f0fef6 DB4ls_all: bei DELTEONE den TYP mit auswerten
anmeld.js: den TYP mit übergeben
Version angepasst
2026-01-20 15:17:13 +01:00
rxf
b77cb63758 sofue: Eintrag in Kalender auch bei 'offen' 2026-01-19 17:15:44 +01:00
rxf
eb46fd0d6d Tippfehler 'jetz' verbessert 2026-01-14 19:05:10 +01:00
rxf
681cf70341 Richtiges Abspeichern des Absagedatums 2026-01-11 09:18:21 +01:00
rxf
01a51a8ed1 Absage-Datum checken 2025-12-24 16:47:37 +01:00
rxf
0e0263abbb Merge branch 'SoFue-mit-Vanilla-javascript' into main 2025-12-24 10:07:52 +01:00
rxf
a8967c707a Version angepasst 2025-12-22 10:32:36 +01:00
rxf
77dc29fa9c Autovervollständigung klappt nun wieder 2025-12-22 10:30:27 +01:00
rxf
2e8e010ceb DB4js_all.php an POHP7.3 angepasst 2025-12-22 10:00:47 +01:00
rxf
61ace47270 Texte bei SoFü angepasst in DB4js_all.php 2025-12-20 20:07:15 +01:00
rxf
66953de7f4 Version updated 2025-12-20 16:59:15 +01:00
rxf
4297a98511 DB4ja_all nicht mehr verwendet
db4js.php wieder auf alte Version
Ebenso bei kalender in index von kalender
2025-12-03 11:18:45 +01:00
11 changed files with 405 additions and 178 deletions

View File

@@ -1,39 +1,11 @@
<?php <?php
# Hier werden die Anfragen vom Javascript verarbeitet und die
# Datenbank bedient # Datenbank bedient
include 'config_stern.php'; include 'config_stern.php';
include 'phpmailer/dosendmail.php'; include 'phpmailer/dosendmail.php';
// ===== Request-Daten verarbeiten =====
// Unterstützt sowohl JSON als auch FormData
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Prüfe Content-Type
$contentType = $_SERVER['CONTENT_TYPE'] ?? $_SERVER['HTTP_CONTENT_TYPE'] ?? '';
if (strpos($contentType, 'application/json') !== false) {
// JSON-Daten
$jsonData = file_get_contents('php://input');
$_POST = json_decode($jsonData, true);
// Debug-Logging
error_log("=== PHP JSON DEBUG ===");
error_log("Content-Type: " . $contentType);
error_log("Raw JSON: " . $jsonData);
error_log("Decoded POST: " . print_r($_POST, true));
error_log("=====================");
}
// Bei FormData ist $_POST bereits automatisch gefüllt
else {
error_log("=== PHP FormData DEBUG ===");
error_log("Content-Type: " . $contentType);
error_log("POST data: " . print_r($_POST, true));
error_log("==========================");
}
}
// Ab hier bleibt alles gleich
$cmd = $_POST["cmd"] ?? '';
// Holen der Einträge in der anmelde-Datenbank für den selektierten Tag // Holen der Einträge in der anmelde-Datenbank für den selektierten Tag
// Parameter // Parameter
@@ -89,7 +61,11 @@ function getOneBEO($kurz, $what)
{ {
global $db; global $db;
$sql_stmt = "SELECT $what FROM beos where kürzel='$kurz'"; if ($what == 'true') {
$sql_stmt = "SELECT * FROM beos where name='$kurz'";
} else {
$sql_stmt = "SELECT $what FROM beos where kürzel='$kurz'";
}
$erg = array(); $erg = array();
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db)); $result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
$data = mysqli_fetch_assoc($result); $data = mysqli_fetch_assoc($result);
@@ -146,7 +122,7 @@ function getTeilnehmer($seed,$isid,$withdate)
// Daten aller Teilnehmer ab eines Führungsdatumns abholen // Daten aller Teilnehmer ab eines Führungsdatumns abholen
// Parameter: // Parameter:
// $fid: Führungsdatum, ab dem die Info geholt wird // $fid: Führungsdatum, ab dem die Info geholt wirdTeilnehmer - ID
// Return: // Return:
// Dict mit allen Daten des Teilnehmers // Dict mit allen Daten des Teilnehmers
function getAllTeilnehmer($fdatum) function getAllTeilnehmer($fdatum)
@@ -167,10 +143,6 @@ function getAllTeilnehmer($fdatum)
// die Daten der Führungen in dem Bereich start - end // die Daten der Führungen in dem Bereich start - end
// in ein Array als ISO8601 holen // in ein Array als ISO8601 holen
// Parameter // Parameter
@@ -178,14 +150,10 @@ function getAllTeilnehmer($fdatum)
// $end -> bis zu diesem Datum // $end -> bis zu diesem Datum
// Retunrn: // Retunrn:
// Array mit den Daten in ISO8601 // Array mit den Daten in ISO8601
function getFuehrungen($start, $end, $typ) { function getFuehrungen($start, $end) {
global $db; global $db;
$erg = []; $erg = array();
$table = 'fdatum1'; $sql_sel = "SELECT * FROM fdatum1 where datum >= '$start' AND datum <= '$end' ORDER BY datum ASC";
if ($typ == 'sonnen') {
$table = 'sonnedatum';
}
$sql_sel = "SELECT * FROM $table where datum >= '$start' AND datum <= '$end' ORDER BY datum ASC";
$result = mysqli_query($db, $sql_sel) or die(mysqli_error($db)); $result = mysqli_query($db, $sql_sel) or die(mysqli_error($db));
while ($row = mysqli_fetch_assoc($result)) { while ($row = mysqli_fetch_assoc($result)) {
foreach ($row as $key => $value) { foreach ($row as $key => $value) {
@@ -225,7 +193,7 @@ function getNextFuehrungen($soviel, $fid) {
function updateTeilnehmer_fdate($id, $fdatum, $fid) { function updateTeilnehmer_fdate($id, $fdatum, $fid) {
global $db; global $db;
$sql_stmt = "UPDATE anmeldungen SET fdatum=$fdatum,fid=$fid, abgesagt=NULL where id=$id"; $sql_stmt = "UPDATE anmeldungen SET fdatum=$fdatum,fid=$fid where id=$id";
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db)); $result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
return $result; return $result;
} }
@@ -298,17 +266,6 @@ function getOneDate($id) {
return $data; return $data;
} }
// aus fdatum die div. Datumsteile hole
function getTimeByDate($dt, $typ) {
global $db;
if ($typ == 'sonnen')
return '11 Uhr';
$sql_stmt = "SELECT uhrzeit FROM fdatum1 WHERE datum='$dt'";
$result = mysqli_query($db, $sql_stmt) or die(mysqli_error($db));
$data = mysqli_fetch_assoc($result);
return $data['uhrzeit'];
}
function insertteilnehmer($data) { function insertteilnehmer($data) {
global $db; global $db;
$name = $data['name']; $name = $data['name'];
@@ -464,15 +421,31 @@ function getOneRecordTermin($termin) {
return $erg; return $erg;
} }
/*
// Ein Record von den Sonderführungen mit der ID $id holen und kompleet übermitteln
function getOneSonderTeilnehmer($id) {
global $db;
$query = "select * from SoFue2 where id = $id";
$result = mysqli_query($db, $query) or die(mysqli_error($db));
while ($row = mysqli_fetch_assoc($result)) {
foreach ($row as $key => $value) {
$entry[$key] = $value;
}
$erg[] = $entry;
}
return $erg;
}
$_POST = json_decode(file_get_contents('php://input'), true); $_POST = json_decode(file_get_contents('php://input'), true);
$erg = ""; $erg = "";
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$cmd = $_POST["cmd"]; $cmd = $_POST["cmd"];
*/ /*
$x = "["; $x = "[";
foreach ($_POST as $key => $value) { foreach ($_POST as $key => $value) {
if(gettype($value) == "array") { if(gettype($value) == "array") {
@@ -481,7 +454,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$x = $x . $key . " => " . $value . ","; $x = $x . $key . " => " . $value . ",";
} }
$x = $x . "]"; $x = $x . "]";
*/
switch ($cmd) { switch ($cmd) {
case 'GET_ANMELD': case 'GET_ANMELD':
$erg = getAnmeldungen($_POST['id']); $erg = getAnmeldungen($_POST['id']);
@@ -521,9 +494,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
case 'GET_ONE_DATE': case 'GET_ONE_DATE':
$erg = getOneDate($_POST['fid']); $erg = getOneDate($_POST['fid']);
break; break;
case 'GET_TIME_BY_DATE':
$erg = getTimeByDate($_POST['dt'], $_POST['typ']);
break;
case 'GET_ALLTEILN': case 'GET_ALLTEILN':
$erg = getAllTeilnehmer($_POST['fdatum']); $erg = getAllTeilnehmer($_POST['fdatum']);
break; break;
@@ -554,7 +524,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$erg = getTeilnehmer(-1, true, false); $erg = getTeilnehmer(-1, true, false);
break; break;
case 'GET_FUEHRUNGEN': case 'GET_FUEHRUNGEN':
$erg = getFuehrungen($_POST['start'], $_POST['end'], $_POST['typ']); $erg = getFuehrungen($_POST['start'], $_POST['end']);
break; break;
case 'PUT_FDATES': case 'PUT_FDATES':
$erg = putFdates($_POST['data']); $erg = putFdates($_POST['data']);
@@ -594,9 +564,14 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
case 'GET_ONETERMIN': case 'GET_ONETERMIN':
$erg = getOneRecordTermin($_POST["termin"]); $erg = getOneRecordTermin($_POST["termin"]);
break; break;
case 'GET_ONESONDERTEILNEHMER':
$erg = getOneSonderTeilnehmer($_POST["id"]);
break;
default: default:
$erg = ['error' => 'Unknown POST-Command', 'cmd' => $cmd, 'params' => $x]; $erg = ['error' => 'Unknown POST-Command', 'cmd' => $cmd, 'params' => $x];
} }
} else {
/* /*
$x = "["; $x = "[";
foreach ($_GET as $key => $value) { foreach ($_GET as $key => $value) {
@@ -604,7 +579,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
} }
$x = $x . "]"; $x = $x . "]";
*/ */
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
$cmd = $_GET['cmd']; $cmd = $_GET['cmd'];
switch ($cmd) { switch ($cmd) {
case 'GET_FDATES': case 'GET_FDATES':

View File

@@ -48,9 +48,70 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
exit; exit;
} }
// Früher Lebenszeichen-Check: hilft zu unterscheiden, ob der Parser/Include scheitert
if (isset($_GET['alive']) && $_GET['alive'] === '1') {
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['alive' => true, 'ts' => date('c')]);
exit;
}
// ---- Fehlerbehandlung ---- // ---- Fehlerbehandlung ----
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set('display_errors', 0); // Keine direkten Fehlerausgaben ini_set('display_errors', 0); // Keine direkten Fehlerausgaben
ini_set('log_errors', '1');
// Schreibe Fehler in ein projektlokales Logfile, damit /var/log nicht nötig ist
// Stelle sicher, dass der Webserver Schreibrechte hat (www-data/apache user)
ini_set('error_log', __DIR__ . '/db4js_error.log');
// Signalisiere dem config_stern.php, dass kein mysqli-Connect durchgeführt werden soll
if (!defined('DB4JS_ALL')) {
define('DB4JS_ALL', true);
}
// Lokales Logging initialisieren: Logdatei anlegen, wenn möglich
function setupLocalLogging(): void {
try {
$logFile = ini_get('error_log');
if (!$logFile) {
$logFile = __DIR__ . '/db4js_error.log';
ini_set('error_log', $logFile);
}
if (!file_exists($logFile)) {
// create empty file
@file_put_contents($logFile, "");
}
// Testeintrag
@error_log('DB4js_all LOG-INIT OK -> ' . $logFile);
} catch (Throwable $e) {
// still attempt a fallback
@file_put_contents(__DIR__ . '/db4js_error.log', 'DB4js_all LOG-INIT FAIL: ' . $e->getMessage() . "\n", FILE_APPEND);
}
}
setupLocalLogging();
// Zusätzliche robuste Fehler- und Request-Logs für Server-Diagnose
register_shutdown_function(function () {
$err = error_get_last();
if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
error_log('DB4js_all FATAL: ' . $err['message'] . ' @' . ($err['file'] ?? '-') . ':' . ($err['line'] ?? '-'));
// Liefere eine JSON-Antwort, damit Clients keinen leeren Body sehen
http_response_code(500);
echo json_encode(['error' => 'Internal error (fatal)', 'details' => 'See server logs'], JSON_UNESCAPED_UNICODE);
}
});
// Basis-Request-Logging (Content-Type, Methode, Rohdaten) zur 500-Analyse
try {
$ct = $_SERVER['CONTENT_TYPE'] ?? $_SERVER['HTTP_CONTENT_TYPE'] ?? '';
$meth = $_SERVER['REQUEST_METHOD'] ?? '';
$rawPreview = '';
$rawBody = file_get_contents('php://input');
if ($rawBody !== false) {
$rawPreview = substr($rawBody, 0, 512);
}
error_log('DB4js_all REQ: method=' . $meth . ' ct=' . $ct . ' raw=' . $rawPreview);
} catch (Throwable $e) {
// Ignoriere Logging-Fehler
}
// ---- Konstanten für Tabellen ---- // ---- Konstanten für Tabellen ----
const TBL_SOFUE = 'SoFue2'; const TBL_SOFUE = 'SoFue2';
@@ -105,7 +166,7 @@ function ensureAuth(): void
} }
// ---- Input Laden (JSON bevorzugt, Fallback FormData/Query) ---- // ---- Input Laden (JSON bevorzugt, Fallback FormData/Query) ----
$raw = file_get_contents('php://input'); $raw = $rawBody ?? file_get_contents('php://input');
$input = []; $input = [];
if ($raw !== false && strlen(trim($raw)) > 0) { if ($raw !== false && strlen(trim($raw)) > 0) {
$decoded = json_decode($raw, true); $decoded = json_decode($raw, true);
@@ -135,7 +196,8 @@ class DB
public static function conn(): PDO public static function conn(): PDO
{ {
if (self::$pdo === null) { if (self::$pdo === null) {
require_once __DIR__ . '/config_stern.php'; // require_once __DIR__ . '/config_stern.php';
include "config_stern.php";
// config_stern.php sollte $host,$dbase,$user,$pass setzen // config_stern.php sollte $host,$dbase,$user,$pass setzen
$hostEnv = getenv('DB_HOST') ?: ($host ?? 'localhost'); $hostEnv = getenv('DB_HOST') ?: ($host ?? 'localhost');
$nameEnv = getenv('DB_NAME') ?: ($dbase ?? 'sternwarte'); $nameEnv = getenv('DB_NAME') ?: ($dbase ?? 'sternwarte');
@@ -293,9 +355,10 @@ class RepoAnmeld
$id $id
]); ]);
} }
public static function delete(int $id): int public static function delete(int $id, string $typ): int
{ {
return DB::exec("DELETE FROM " . TBL_ANMELD . " WHERE id=?", [$id]); $table = ($typ == 'regular') ? TBL_ANMELD : TBL_SONNEANMELD;
return DB::exec("DELETE FROM " . $table . " WHERE id=?", [$id]);
} }
public static function bulkUpdateField(array $ids, string $field, $value): int public static function bulkUpdateField(array $ids, string $field, $value): int
{ {
@@ -306,6 +369,7 @@ class RepoAnmeld
} }
$ids = array_values(array_filter(array_map('intval', $ids), function ($v) { return $v > 0; })); $ids = array_values(array_filter(array_map('intval', $ids), function ($v) { return $v > 0; }));
if (empty($ids)) return 0; if (empty($ids)) return 0;
$placeholders = implode(',', array_fill(0, count($ids), '?')); $placeholders = implode(',', array_fill(0, count($ids), '?'));
$sql = "UPDATE " . TBL_ANMELD . " SET $field=? WHERE id IN ($placeholders)"; $sql = "UPDATE " . TBL_ANMELD . " SET $field=? WHERE id IN ($placeholders)";
$params = array_merge([$value], $ids); $params = array_merge([$value], $ids);
@@ -762,7 +826,7 @@ class RepoStatistikJahre
{ {
$sql = "SELECT YEAR(datum) as jahr FROM " . self::TBL . " GROUP BY YEAR(datum) ORDER BY YEAR(datum) DESC"; $sql = "SELECT YEAR(datum) as jahr FROM " . self::TBL . " GROUP BY YEAR(datum) ORDER BY YEAR(datum) DESC";
$rows = DB::all($sql); $rows = DB::all($sql);
return array_map(fn($r) => (int)$r['jahr'], $rows); return array_map(function($r) { return (int)$r['jahr']; }, $rows);
} }
} }
@@ -865,7 +929,7 @@ class Mailer
$ccList = $cc ? [$cc] : []; $ccList = $cc ? [$cc] : [];
$result = sendmail( $result = sendmail(
$subject, $subject,
'info@sternwarte-welzheim.de', 'sternwarte.welzheim@gmx.de',
$body, $body,
$ccList, $ccList,
[], [],
@@ -885,9 +949,9 @@ class Mailer
require_once __DIR__ . '/phpmailer/dosendmail.php'; require_once __DIR__ . '/phpmailer/dosendmail.php';
// sanitize lists // sanitize lists
$toList = array_values(array_filter($toList, fn($v) => is_string($v) && trim($v) !== '')); $toList = array_values(array_filter($toList, function($v) { return is_string($v) && trim($v) !== ''; }));
$ccList = array_values(array_filter($ccList, fn($v) => is_string($v) && trim($v) !== '')); $ccList = array_values(array_filter($ccList, function($v) { return is_string($v) && trim($v) !== ''; }));
$bccList = array_values(array_filter($bccList, fn($v) => is_string($v) && trim($v) !== '')); $bccList = array_values(array_filter($bccList, function($v) { return is_string($v) && trim($v) !== ''; }));
if (empty($toList)) { if (empty($toList)) {
return false; return false;
@@ -895,7 +959,7 @@ class Mailer
$result = sendmail( $result = sendmail(
$subject, $subject,
'info@sternwarte-welzheim.de', 'sternwarte.welzheim@gmx.de',
$body, $body,
$ccList, $ccList,
$bccList, $bccList,
@@ -915,6 +979,8 @@ class Commands
{ {
public const MAP = [ public const MAP = [
'PING' => 'Health-Check', 'PING' => 'Health-Check',
'PING_LOG' => 'Schreibt Testzeile ins Log',
'READ_LOG' => 'Liest letzte N Zeilen aus lokalem Log',
'GET_ANMELD' => 'Liste Anmeldungen für fid/Datum', 'GET_ANMELD' => 'Liste Anmeldungen für fid/Datum',
'GET_ANMELDNEW' => 'Anmeldungen-Varianten (special/date)', 'GET_ANMELDNEW' => 'Anmeldungen-Varianten (special/date)',
'GET_TEILN_ID' => 'Teilnehmer nach id', 'GET_TEILN_ID' => 'Teilnehmer nach id',
@@ -977,6 +1043,27 @@ try {
case 'PING': case 'PING':
respond(['pong' => true, 'timestamp' => date('c')]); respond(['pong' => true, 'timestamp' => date('c')]);
case 'PING_LOG':
$logFile = ini_get('error_log') ?: (__DIR__ . '/db4js_error.log');
error_log('DB4js_all PING_LOG at ' . date('c'));
$ok = file_exists($logFile);
respond(['ok' => $ok, 'logfile' => $logFile]);
case 'READ_LOG':
$logFile = ini_get('error_log') ?: (__DIR__ . '/db4js_error.log');
$lines = (int)($input['lines'] ?? 100);
$lines = max(10, min($lines, 1000));
if (!is_readable($logFile)) {
respond(['error' => 'Logfile not readable', 'logfile' => $logFile], 404);
}
// Tail simple implementation
$content = @file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$out = [];
if (is_array($content)) {
$out = array_slice($content, -$lines);
}
respond(['logfile' => $logFile, 'lines' => $lines, 'data' => $out]);
// Öffentliche Führungen // Öffentliche Führungen
case 'GET_ANMELD': case 'GET_ANMELD':
// Backcompat: if an 8+ digit numeric 'id' is passed, treat it as date (fdatum) // Backcompat: if an 8+ digit numeric 'id' is passed, treat it as date (fdatum)
@@ -1029,10 +1116,10 @@ try {
RepoAnmeld::update((int)$input['id'], $input); RepoAnmeld::update((int)$input['id'], $input);
respond(['success' => true]); respond(['success' => true]);
case 'DELETE_TLN': case 'DELETE_TLN':
RepoAnmeld::delete((int)$input['id']); RepoAnmeld::delete((int)$input['id'], $input['typ']);
respond(['success' => true]); respond(['success' => true]);
case 'DELETEONE': // alias for legacy case 'DELETEONE': // alias for legacy
RepoAnmeld::delete((int)$input['id']); RepoAnmeld::delete((int)$input['id'], $input['typ']);
respond(['success' => true]); respond(['success' => true]);
case 'UPDATE_TLN_BULK': case 'UPDATE_TLN_BULK':
if (!isset($input['ids'], $input['field'], $input['values'])) respondError('Missing fields'); if (!isset($input['ids'], $input['field'], $input['values'])) respondError('Missing fields');
@@ -1122,40 +1209,128 @@ try {
case 'SENDMAILZUSAGE': case 'SENDMAILZUSAGE':
$info = RepoSoFue::getById((int)$input['id']); $info = RepoSoFue::getById((int)$input['id']);
if (!$info) respondError('Führung nicht gefunden', 404); if (!$info) respondError('Führung nicht gefunden', 404);
$subject = 'Ihre Sonderführung am ' . date('d.m.Y', strtotime($input['termin'])); $ma = RepoBeos::getByName($input['mitarbeiter']);
$body = "Hallo {$info['name']}, Ihre Sonderführung am " . $input['termin'] . " findet mit Mitarbeiter " . $input['mitarbeiter'] . " statt."; $ma_name = $ma['name'];
$ok = Mailer::sendPlain($info['email'], $subject, $body, 'info@sternwarte-welzheim.de'); $ma_vorname = $ma['vorname'];
$gender = $ma['gender'] == 'm';
$ma_mail = $ma['email_1'];
$ge1 = $gender ? "unser ehrenamtlicher Mitarbeiter, Herr" : "unsere ehrenamtliche Mitarbeiterin, Frau";
$ge2 = $gender ? "ihn" : "sie";
$ge3 = $gender ? "Herrn" : "Frau";
$dt = date('d.m.Y H:i', strtotime($input['termin']));
$subject = 'ZUSAGE - Sternführung am ' . $dt . ' Uhr';
$body = "
Guten Tag,
für Ihren Wunschtermin, {$dt} Uhr, hat sich {$ge1} {$ma_vorname} {$ma_name} bereit erklärt,
die Sonderführung zu übernehmen. Sie erreichen {$ge2} über die e-mail-Adresse: {$ma_mail}
Um nähere Besuchsmodalitäten zu klären, bitten wir Sie, mit {$ge3} {$ma_name} Kontakt aufzunehmen.
Wir bitten Sie, die Spende in Höhe von €50.00 auf unten aufgeführtes Konto zu überweisen oder in bar zur Führung mitzubringen.
Gesellschaft zur Förderung des Planetariums Stuttgart und der Sternwarte Welzheim e.V.
BANKVERBINDUNG: Deutsche Bank AG Stuttgart
IBAN DE18 6007 0070 0122 0383 00
BIC: DEUTDESSXXX
Mit sternfreundlichen Grüßen
Reinhard X. Fürst
Sternwarte Welzheim
";
$ok = Mailer::sendPlain($info['email'], $subject, $body, 'rexfue@gmail.com');
respond(['success' => $ok]); respond(['success' => $ok]);
case 'SENDMAIL2BEO': case 'SENDMAIL2BEO':
$mail = RepoBeos::email($input['ma']); $mail = RepoBeos::email($input['ma']);
$vor = RepoBeos::vorname($input['ma']); $vor = RepoBeos::vorname($input['ma']);
$dt = date('d.m.Y H:i', strtotime($input['termin']));
if (!$mail) respondError('Mitarbeiter nicht gefunden', 404); if (!$mail) respondError('Mitarbeiter nicht gefunden', 404);
$info = RepoSoFue::getByTermin($input['termin']); $info = RepoSoFue::getByTermin($input['termin']);
if (!$info) respondError('Führung nicht gefunden', 404); if (!$info) respondError('Führung nicht gefunden', 404);
$subject = 'Sonderführung am ' . date('d.m.Y', strtotime($input['termin'])); $subject = 'Vereinbarte Sonderführung am ' . date('d.m.Y', strtotime($input['termin']));
$body = "Hallo $vor, du hast eine Sonderführung am {$input['termin']}. Teilnehmer: " . ($info['anzahl'] ?? '-'); $body = "
$ok = Mailer::sendPlain($mail, $subject, $body, 'info@sternwarte-welzheim.de'); Hallo " . $vor .",
vielen Dank für die Bereitschaft, die Sonderführung am {$dt} zu übernehmen.
Bitte den Termin nicht vergessen und bitte ggf. auch das Teammitglied, das die
Führung mitmacht, informieren.
Der Termin wurde in den Sternwartenkalender eingetragen.
Die Kontaktdaten sind auf der Sonderführungsseite ( https://sternwarte-welzheim.de/intern/sofue/sofue.php ) zu finden.
Viele Grüße
Reinhard
Diese Meldung wurde automatisch erzeugt. Es kann nicht geantwortet werden.";
$ok = Mailer::sendPlain($mail, $subject, $body, 'rexfue@gmail.com');
respond(['success' => $ok]); respond(['success' => $ok]);
case 'SENDMAIL2LISTE': case 'SENDMAIL2LISTE':
$info = RepoSoFue::getById((int)$input['id']); $info = RepoSoFue::getById((int)$input['id']);
if (!$info) respondError('Führung nicht gefunden', 404); if (!$info) respondError('Führung nicht gefunden', 404);
$to = $input['to'] ?? LISTE_EMAIL; $to = $input['to'] ?? LISTE_EMAIL;
$subject = 'Neue Anfrage Sonderführung ' . date('d.m.Y', strtotime($info['wtermin'])); $subject = 'Neue Anfrage Sonderführung am ' . date('d.m.Y', strtotime($info['wtermin']));
$body = 'Neue Anfrage: ' . $info['name'] . ' Personen: ' . ($info['anzahl'] ?? '-'); $body = "
$ok = Mailer::sendPlain($to, $subject, $body); Liebe BEOs,
wer kann folgende Sonderführung übernehmen?
Viele Grüße
Reinhard
---------------------------------------------------------------------------------------------------";
$body = $body . "
Name, Vorname: " . $info['name'] . " " . $info['vorname'] . "
Verein / Organisation : " . $info['verein'] . "
Wunsch - Termin: " . $info['wtermin'] . "
Teilnehmerzahl ca.: " . $info['anzahl'] . "
Weitere Fragen oder Mitteilungen:
" . $info['mitteilung'] . "
Spendenbescheinigung: \t" . $info['spende'] . "
---------------------------------------------------------------------------------------------------";
$ok = Mailer::sendPlain($to, $subject, $body);
respond(['success' => $ok]); respond(['success' => $ok]);
// Kalender // Kalender
case 'PUT2KALENDER': case 'PUT2KALENDER':
if (!isset($input['id'], $input['termin'], $input['mitarbeiter'])) respondError('Missing fields'); if (!isset($input['id'], $input['termin'], $input['mitarbeiter'])) respondError('Missing fields');
error_log('Kalender-Eintrag: ' . $input['id'] . ' ' . $input['termin'] . ' ' . $input['mitarbeiter']);
// Sonderführung laden
$sofue = RepoSoFue::getById((int)$input['id']);
if (!$sofue) respondError('Sonderführung nicht gefunden', 404);
// Datum aus termin extrahieren und in YYYYMMDD Format konvertieren
$terminDate = new DateTime($input['termin']);
$dateStr = $terminDate->format('Y-m-d H:i');
$endTime = $terminDate->modify('+2hours');
$endStr = $endTime->format('Y-m-d H:i');
// Titel mit Mitarbeiter für Kalendereintrag erstellen
$title = "WK, SF " . trim($sofue['name']) . ", " . $input['mitarbeiter'];
// Kalendereintrag erstellen
RepoKalender::insert([
'start' => $dateStr,
'end' => $endStr,
'title' => $title,
'description' => ''
]);
error_log('Kalender-Eintrag erstellt: ' . $input['id'] . ' ' . $input['termin'] . ' ' . $input['mitarbeiter']);
respond(['success' => true]); respond(['success' => true]);
case 'GET_FDATES': case 'GET_FDATES':
// Returns führungen for calendar display // Returns führungen for calendar display
$start = $input['start'] ?? date('Ymd'); if (!isset($input['start'], $input['end'])) respondError('start and end required');
$end = $input['end'] ?? date('Ymd', strtotime('+1 year')); // Convert ISO date strings to YYYYMMDD format
$s = date('Ymd', strtotime($start)); $startObj = new DateTime($input['start']);
$e = date('Ymd', strtotime($end)); $endObj = new DateTime($input['end']);
$s = $startObj->format('Ymd');
$e = $endObj->format('Ymd');
$sql = "SELECT * FROM " . TBL_FDATUM . " WHERE datum >= ? AND datum <= ? ORDER BY datum ASC"; $sql = "SELECT * FROM " . TBL_FDATUM . " WHERE datum >= ? AND datum <= ? ORDER BY datum ASC";
$rows = DB::all($sql, [$s, $e]); $rows = DB::all($sql, [$s, $e]);
$result = []; $result = [];
@@ -1164,12 +1339,13 @@ try {
$result[] = [ $result[] = [
'start' => $r['datum'], 'start' => $r['datum'],
'uhr' => substr($r['uhrzeit'] ?? '', 0, 2), 'uhr' => substr($r['uhrzeit'] ?? '', 0, 2),
'title' => $r['gruppe'] ?? '', 'title' => $r['grp'] ?? '',
'count' => $count 'count' => $count
]; ];
} }
respond($result); respond($result);
case 'GET_CALENTRIES': case 'GET_CALENTRIES':
if (!isset($input['start'], $input['end'])) respondError('start and end required');
respond(RepoKalender::getEntries($input['start'], $input['end'])); respond(RepoKalender::getEntries($input['start'], $input['end']));
case 'PUT_CALENTRY': case 'PUT_CALENTRY':
RepoKalender::insert($input['data']); RepoKalender::insert($input['data']);

View File

@@ -1,5 +1,6 @@
# Production Environment Variables # Production Environment Variables
VITE_API_URL=/intern/sofue/php/sofueDB.php # VITE_API_URL=/intern/sofue/php/sofueDB.php
VITE_API_URL=/DB4js_all.php # Lokales Development Backend (über Proxy)
# HTTP Basic Authentication # HTTP Basic Authentication
VITE_API_USERNAME=beogruppe VITE_API_USERNAME=beogruppe

View File

@@ -30,7 +30,7 @@ V 0.0 2019-02-04 rxf
*/ */
"use strict" "use strict"
const DEVELOP=0; // 1 -> Entwicklung 0-> Produktion const DEVELOP=1; // 1 -> Entwicklung 0-> Produktion
const moment = require('moment'); const moment = require('moment');
const axios = require('axios'); const axios = require('axios');

View File

@@ -55,7 +55,7 @@ Beobachtergruppe Sternwarte Welzheim`
let abgesagt = null let abgesagt = null
let actualdate; let actualdate;
let isSmallScreen = false let isSmallScreen = false
let DateTime = luxon.DateTime const DateTime = luxon.DateTime
function $(selector) { function $(selector) {
@@ -70,7 +70,7 @@ Beobachtergruppe Sternwarte Welzheim`
body.typ = query.typ; body.typ = query.typ;
const response = await fetch(ajaxURL, { const response = await fetch(ajaxURL, {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/js'}, headers: {'Content-Type': 'application/json'},
body: JSON.stringify(body) body: JSON.stringify(body)
}); });
return await response.json(); return await response.json();
@@ -80,7 +80,7 @@ Beobachtergruppe Sternwarte Welzheim`
body.typ = query.typ; body.typ = query.typ;
const response = await fetch(ajaxURL, { const response = await fetch(ajaxURL, {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/js'}, headers: {'Content-Type': 'application/json'},
body: JSON.stringify(body) body: JSON.stringify(body)
}); });
return await response.json(); return await response.json();
@@ -99,9 +99,17 @@ Beobachtergruppe Sternwarte Welzheim`
} }
async function storeAbsage(ids) { async function storeAbsage(ids) {
if (!DateTime || typeof DateTime.now !== 'function') {
console.error('Luxon DateTime ist nicht verfügbar');
throw new Error('Datum kann nicht erstellt werden - Luxon nicht geladen');
}
const dt = DateTime.now() const dt = DateTime.now()
const jetzt = dt.toFormat('yyyy-LL-dd HH:mm') const jetzt = dt.toFormat('yyyy-LL-dd HH:mm:ss')
const update = { cmd: 'UPDATE_TLN_BULK', field: 'abgesagt', ids: ids, values: [`"${jetzt}"`] }; if (!jetzt || jetzt === 'undefined' || jetzt.includes('undefined')) {
console.error('Ungültiges Datum generiert:', jetzt);
throw new Error('Ungültiges Datum erstellt');
}
const update = { cmd: 'UPDATE_TLN_BULK', field: 'abgesagt', ids: ids, values: [jetzt] };
await putToDbase(update); await putToDbase(update);
abgesagt = jetzt abgesagt = jetzt
} }
@@ -122,7 +130,7 @@ Beobachtergruppe Sternwarte Welzheim`
// Teilnehmer aus 'anmeldungen' austragen und den count in 'fdatum1' anpassen // Teilnehmer aus 'anmeldungen' austragen und den count in 'fdatum1' anpassen
const austragen = async (teilnehmer) => { const austragen = async (teilnehmer) => {
let update = {cmd: 'DELETEONE', id: parseInt(teilnehmer.id)} let update = {cmd: 'DELETEONE', id: parseInt(teilnehmer.id), typ: query.typ}
const erg1 = await putToDbase(update) const erg1 = await putToDbase(update)
update = {cmd: 'UPDATECOUNT', date: parseInt(teilnehmer.fdatum), anzahl: parseInt(teilnehmer.anzahl)} update = {cmd: 'UPDATECOUNT', date: parseInt(teilnehmer.fdatum), anzahl: parseInt(teilnehmer.anzahl)}
const erg2 = await putToDbase(update) const erg2 = await putToDbase(update)
@@ -304,29 +312,63 @@ Beobachtergruppe Sternwarte Welzheim`
const grundIndex = Array.from($all('input[name=grund]')).find(el => el.checked)?.value || 0; const grundIndex = Array.from($all('input[name=grund]')).find(el => el.checked)?.value || 0;
absagegrund = absagegrundListe[grundIndex]; absagegrund = absagegrundListe[grundIndex];
await storeAbsage(liste.ids); // Versuche das Absagedatum zu speichern, aber breche nicht ab wenn es fehlschlägt
let datumGespeichert = false;
if (query.typ !== 'sonnen') { try {
await fetch('https://laufschrift.rexfue.de/switch/switch_on') await storeAbsage(liste.ids);
datumGespeichert = true;
} catch (error) {
console.error('Fehler beim Speichern des Absagedatums:', error);
// Warnung anzeigen, aber weitermachen
console.warn('Absagedatum konnte nicht gespeichert werden, aber Mail wird trotzdem versendet');
} }
// Laufschrift einschalten (falls regular)
if (query.typ !== 'sonnen') {
try {
await fetch('https://laufschrift.rexfue.de/switch/switch_on')
} catch (error) {
console.error('Laufschrift konnte nicht eingeschaltet werden:', error);
}
}
// Mail senden (wichtigster Teil!)
bodyText = bodytext.replace("{absagegrund}", absagegrund); bodyText = bodytext.replace("{absagegrund}", absagegrund);
const mailRet = await fetchFromDbase({ try {
cmd: 'SENDMYMAIL', const mailRet = await fetchFromDbase({
to: ['rexfue@gmail.com'], cmd: 'SENDMYMAIL',
betreff: betreff, to: ['rexfue@gmail.com'],
body: bodyText, betreff: betreff,
bcc: liste.emails body: bodyText,
}); bcc: liste.emails
if (mailRet.error) { });
$('#errortext').innerHTML = mailRet.errortext
if (mailRet.error) {
$('#errortext').innerHTML = mailRet.errortext
$('#errordialog-ok').addEventListener('click', () => $('#errordialog').close())
$('#errordialog').showModal();
return;
}
console.log("Mailret: ", mailRet, "Gesendet an: ", liste.emails)
// Zeige Warnung an, wenn Datum nicht gespeichert werden konnte
if (!datumGespeichert) {
$('#errortext').innerHTML = `<strong>Hinweis:</strong><br>Die Absage-Mail wurde erfolgreich versendet.<br><br>Das Absagedatum konnte jedoch nicht in der Datenbank gespeichert werden. Bitte notieren Sie manuell, dass die Absage gesendet wurde.`;
$('#errordialog-ok').addEventListener('click', () => $('#errordialog').close())
$('#errordialog').showModal();
}
$('#absagen').innerHTML = TEXTE.absagebutton(abgesagt)
$('#absagedialog').close();
} catch (error) {
console.error('Fehler beim Mail-Versand:', error);
$('#errortext').innerHTML = `<strong>Fehler beim Versenden der Absage-Mail:</strong><br>${error.message}`;
$('#errordialog-ok').addEventListener('click', () => $('#errordialog').close()) $('#errordialog-ok').addEventListener('click', () => $('#errordialog').close())
$('#errordialog').showModal(); $('#errordialog').showModal();
$('#absagedialog').close();
} }
console.log("Mailret: ", mailRet, "Gesendet an: ", liste.emails)
$('#absagen').innerHTML = TEXTE.absagebutton(abgesagt)
$('#absagedialog').close();
}); });
$('#absagedialog-cancel').addEventListener('click', () => { $('#absagedialog-cancel').addEventListener('click', () => {

View File

@@ -1,17 +1,27 @@
// VersiosNummern und -Geschichte // VersiosNummern und -Geschichte
const VERSION="1.10.0"; const VERSION="1.12.1";
const VDATE="2025-11-17"; const VDATE="2026-01-20";
/* History /* History
Rev. Datum Entwickler Rev. Datum Entwickler
1.12.1 2026-01-20 rxf
- bei DELETEONE den typ mit übergeben (sonst geht storno bei sonne nicht)
1.12.0 2026-01-11 rxf
- Abmeldedatum richtig als einfacher String mit Sekunden abspeichern
1.11.0 2025-12-24 rxf
- Wenn das Absagedatum ungültig ist, eine Fehlermeldung
erzeugen, aber die Mails trotzdem versenden
1.10.0 2025-11-17 rxf 1.10.0 2025-11-17 rxf
- als PHP-Interface nun das DB4js_all.php verwendet - als PHP-Interface nun das DB4js_all.php verwendet
- unter Tabelle noch die Namen der Führenden anzeigen - unter Tabelle noch die Namen der Führenden anzeigen
1.9.0 2025-11-07 rxf 1.9.0 2025-11-07 rxf
- Datum der Absge mit in der DB (abgesagt). Wird angezeigt, wenn abgesagt wurde. - Datum der Absge mit in der DB (abgesagt). Wird angezeigt, wenn abgesagt wurde.
1.8.1 2025-10-19 rxf 1.8.1 2025-10-19 rxf

30
sternwarte/intern/sofue/js/sofue.js Executable file → Normal file
View File

@@ -284,6 +284,7 @@ function addEditbox(detail) {
//bei der Eingabe der BEOs eine Autovervollständigung durchführen //bei der Eingabe der BEOs eine Autovervollständigung durchführen
function buildBeosComplete() { function buildBeosComplete() {
function split( val ) { function split( val ) {
return val.split( /,\s*/ ); return val.split( /,\s*/ );
} }
@@ -291,6 +292,19 @@ function buildBeosComplete() {
return split( term ).pop(); return split( term ).pop();
} }
// Konvertiere beos Array: wenn Objekte, extrahiere die Namen
var beosNames = beos.map(function(item) {
if (typeof item === 'string') {
return item;
} else if (item && item.name) {
return item.name;
} else {
return String(item);
}
});
console.log("buildBeosComplete - Original beos:", beos);
console.log("buildBeosComplete - Converted names:", beosNames);
$( "#curmar" ) $( "#curmar" )
// don't navigate away from the field on tab when selecting an item // don't navigate away from the field on tab when selecting an item
@@ -304,8 +318,11 @@ function buildBeosComplete() {
minLength: 0, minLength: 0,
source: function( request, response ) { source: function( request, response ) {
// delegate back to autocomplete, but extract the last term // delegate back to autocomplete, but extract the last term
response( $.ui.autocomplete.filter( var term = extractLast( request.term );
beos, extractLast( request.term ) ) ); console.log("Searching for:", term);
var filtered = $.ui.autocomplete.filter(beosNames, term);
console.log("Filtered results:", filtered);
response( filtered );
}, },
focus: function() { focus: function() {
// prevent value inserted on focus // prevent value inserted on focus
@@ -551,7 +568,7 @@ function saveSettings() {
doAjaxCall_arr(ajaxURL,cmd,showajaxerg); doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
if(status == 1) { // offen -> mail an Liste if(status == 1) { // offen -> mail an Liste
sendmail2liste(id); sendmail2liste(id, termin);
} }
if (status == 2) { if (status == 2) {
sendmail2beo(id, marb, termin) sendmail2beo(id, marb, termin)
@@ -595,12 +612,15 @@ function showdbase(val) {
} }
// Status wurde auf 'offen' gesetzt -> nun eine Mail an die Liste mit der Anfrage senden // Status wurde auf 'offen' gesetzt -> nun eine Mail an die Liste mit der Anfrage senden
function sendmail2liste(id) { function sendmail2liste(id, termin) {
const liste = 'sternwarte@planetariumsgesellschaft.de'; const liste = 'sternwarte@planetariumsgesellschaft.de';
const cmd = {cmd: 'SENDMAIL2LISTE', id: id, to: liste} let cmd = {cmd: 'SENDMAIL2LISTE', id: id, to: liste}
console.log("Sende mail to Liste"); console.log("Sende mail to Liste");
doAjaxCall_arr(ajaxURL,cmd,showajaxerg); doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
console.log("Mail gesendet"); console.log("Mail gesendet");
// in den Kalender als Platzhalter (mit ??) eintragen
cmd = {cmd: 'PUT2KALENDER', id: id, termin: termin, mitarbeiter: '??'}
doAjaxCall_arr(ajaxURL,cmd,showajaxerg);
} }
// Status wurde auf 'zugesgat' gesetzt -> nun eine Mail an den BEO senden // Status wurde auf 'zugesgat' gesetzt -> nun eine Mail an den BEO senden

View File

@@ -1,17 +1,28 @@
// VersiosNummern und -Geschichte // VersiosNummern und -Geschichte
var VERSION="1.92"; var VERSION="1.95";
var VDATE="2024-09-20"; var VDATE="2026-01-19";
/* History /* History
Rev. Datum Entwickler Rev. Datum Entwickler
1.95 2026-01-19
- Eintrag in den Kalender auch bei 'offen'
1.94 2025-12-22 rxf
- Autocomplete repariert
1.93 2025-12-20 rxf
- Texte in DB4js_all angepasst, so dass sie wie im alten sofue.js erscheinen
- DB4js_all.php nun verwenden
- prüfen auf 'termin === null' ich check1900()
1.92 2024-09-20 rxf 1.92 2024-09-20 rxf
- Probleme mit 'Zusgae sende' behoben - Probleme mit 'Zusgae sende' behoben
- auch bei mehreren BEOs geht nun die Mail richtig - auch bei mehreren BEOs geht nun die Mail richtig
1.91 2024-09-14 rxf 1.91 2024-09-14 rxf
- and den BEOS keine Kontaktdaten mehr senden (die stehen in der Übersichtsseite) - and den BEOS keine Kontaktdaten mehr senden (die stehen in der Übersichtsseite)
1.90 2024-09-02 rxf 1.90 2024-09-02 rxf
- Automatisch Mails senden an Liste bei 'offen' und am BEO und den Anmeldenden bei 'Zusage' - Automatisch Mails senden an Liste bei 'offen' und am BEO und den Anmeldenden bei 'Zusage'

View File

@@ -10,10 +10,10 @@
<link href='lib/main.css' rel='stylesheet'/> <link href='lib/main.css' rel='stylesheet'/>
<link href='css/kalender.css' rel='stylesheet'/> <link href='css/kalender.css' rel='stylesheet'/>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha384-ZvpUoO/+PpLXR1lu4jmpXWu80pZlYUAfxl5NsBMWOEPSjUn/6Z/hRTt8+pR6L4N2" crossorigin="anonymous"></script> <script src='../javascript/jquery-1.11.0.min.js'></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<!-- <script src='/javascript/bootstrap.min.js'></script> --> <!-- <script src='/javascript/bootstrap.min.js'></script> -->
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4/build/global/luxon.min.js"></script> <script src='../javascript/moment.min.js'></script>
<script src='lib/main.js'></script> <script src='lib/main.js'></script>
<script src='js/version.js'></script> <script src='js/version.js'></script>
<script src='js/kalender.js'></script> <script src='js/kalender.js'></script>

View File

@@ -1,10 +1,9 @@
// calendar.js // calendar.js
document.addEventListener('DOMContentLoaded', async function () { document.addEventListener('DOMContentLoaded', async function () {
const DateTime = luxon.DateTime;
const months_short = [0, 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']; const months_short = [0, 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];
const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstg', 'Freitag', 'Samstag', 'Sonntag']; const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstg', 'Freitag', 'Samstag', 'Sonntag'];
const url = '../DB4js_all.php'; const url = '../DB4js.php';
const default_dauer = 90; // Standardführung dauert 90min const default_dauer = 90; // Standardführung dauert 90min
let fuehrungszeiten; let fuehrungszeiten;
let isedit; let isedit;
@@ -231,7 +230,7 @@ document.addEventListener('DOMContentLoaded', async function () {
$('#txtTitle').val(''); $('#txtTitle').val('');
$('#txtBeschr').val(''); $('#txtBeschr').val('');
let ret = await putToDbase({cmd: 'DEL_CALENTRY', id: id}); let ret = await putToDbase({cmd: 'DEL_CALENTRY', id: id});
if (ret.success != true) { if (ret != true) {
alert(`Fehler beim Löschen des Eintrages !`); alert(`Fehler beim Löschen des Eintrages !`);
} }
calendar.refetchEvents(); calendar.refetchEvents();
@@ -292,12 +291,9 @@ document.addEventListener('DOMContentLoaded', async function () {
// Return: // Return:
// entweder die Startzeit, falls gefunden oder aber 20 [Uhr] // entweder die Startzeit, falls gefunden oder aber 20 [Uhr]
function getFuehrungszeitZeit() { function getFuehrungszeitZeit() {
if (fuehrungszeiten && fuehrungszeiten.length > 3 && fuehrungszeiten[3].start) { if (fuehrungszeiten[3].start !== undefined) {
let st = DateTime.fromFormat(String(fuehrungszeiten[3].start), 'yyyyMMdd'); let st = moment(fuehrungszeiten[3].start);
if (fuehrungszeiten[3].uhr) { return st.hour();
st = st.plus({ hours: fuehrungszeiten[3].uhr });
}
return st.hour;
} else { } else {
return 20; return 20;
} }
@@ -313,43 +309,46 @@ document.addEventListener('DOMContentLoaded', async function () {
function fillModal(st_seldate, end_seldate) { function fillModal(st_seldate, end_seldate) {
let start, end; let start, end;
if (isedit) { if (isedit) {
start = DateTime.fromJSDate(st_seldate); start = moment(st_seldate);
end = DateTime.fromJSDate(end_seldate); end = moment(end_seldate);
} else { } else {
start = DateTime.fromJSDate(st_seldate).set({ hour: getFuehrungszeitZeit() }); start = moment(st_seldate);
end = DateTime.fromJSDate(st_seldate).set({ hour: getFuehrungszeitZeit() }).plus({ minutes: default_dauer }); start.hour(getFuehrungszeitZeit());
end = moment(st_seldate);
end.hour(getFuehrungszeitZeit());
end = end.add(default_dauer, 'm');
$('#txtTitle').val(''); $('#txtTitle').val('');
$('#txtBeschr').val(''); $('#txtBeschr').val('');
} }
$('#st_date_day #end_date_day').html(''); $('#st_date_day #end_date_day').html('');
$('#end_date_day').html(''); $('#end_date_day').html('');
for (let i = 1; i <= 31; i++) { for (let i = 1; i <= 31; i++) {
$('#st_date_day').append(`<option ${start.day == i ? 'selected' : ''}>${i}</option>`); $('#st_date_day').append(`<option ${start.date() == i ? 'selected' : ''}>${i}</option>`);
$('#end_date_day').append(`<option ${end.day == i ? 'selected' : ''}>${i}</option>`); $('#end_date_day').append(`<option ${end.date() == i ? 'selected' : ''}>${i}</option>`);
} }
$('#st_date_month #end_date_month').html(''); $('#st_date_month #end_date_month').html('');
$('#end_date_month').html(''); $('#end_date_month').html('');
for (let i = 1; i <= 12; i++) { for (let i = 1; i <= 12; i++) {
$('#st_date_month').append(`<option value=${i} ${start.month == i ? 'selected' : ''}>${months_short[i]}</option>`); $('#st_date_month').append(`<option value=${i} ${(start.month() + 1) == i ? 'selected' : ''}>${months_short[i]}</option>`);
$('#end_date_month').append(`<option value=${i} ${end.month == i ? 'selected' : ''}>${months_short[i]}</option>`); $('#end_date_month').append(`<option value=${i} ${(end.month() + 1) == i ? 'selected' : ''}>${months_short[i]}</option>`);
} }
$('#st_date_year #end_date_year').html(''); $('#st_date_year #end_date_year').html('');
$('#end_date_year').html(''); $('#end_date_year').html('');
for (let i = 2020; i <= 2030; i++) { for (let i = 2020; i <= 2030; i++) {
$('#st_date_year').append(`<option ${start.year == i ? 'selected' : ''}>${i}</option>`); $('#st_date_year').append(`<option ${start.year() == i ? 'selected' : ''}>${i}</option>`);
$('#end_date_year').append(`<option ${end.year == i ? 'selected' : ''}>${i}</option>`); $('#end_date_year').append(`<option ${end.year() == i ? 'selected' : ''}>${i}</option>`);
} }
$('#st_date_hours').html(''); $('#st_date_hours').html('');
$('#end_date_hours').html(''); $('#end_date_hours').html('');
for (let i = 0; i <= 23; i++) { for (let i = 0; i <= 23; i++) {
$('#st_date_hours').append(`<option ${start.hour == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`); $('#st_date_hours').append(`<option ${start.hour() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
$('#end_date_hours').append(`<option ${end.hour == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`); $('#end_date_hours').append(`<option ${end.hour() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
} }
$('#st_date_minutes').html(''); $('#st_date_minutes').html('');
$('#end_date_minutes').html(''); $('#end_date_minutes').html('');
for (let i = 0; i <= 50; i += 10) { for (let i = 0; i <= 50; i += 10) {
$('#st_date_minutes').append(`<option ${start.minute == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`); $('#st_date_minutes').append(`<option ${start.minute() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
$('#end_date_minutes').append(`<option ${end.minute == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`); $('#end_date_minutes').append(`<option ${end.minute() == i ? 'selected' : ''}>${("0" + i).slice(-2)}</option>`);
} }
} }
@@ -388,9 +387,9 @@ document.addEventListener('DOMContentLoaded', async function () {
// Zuerst die regelmäßigen Führungen hole // Zuerst die regelmäßigen Führungen hole
fuehrungszeiten = await fetchFromDbase({cmd: 'GET_FDATES', start: start, end: end}); fuehrungszeiten = await fetchFromDbase({cmd: 'GET_FDATES', start: start, end: end});
for (let i = 0; i < fuehrungszeiten.length; i++) { for (let i = 0; i < fuehrungszeiten.length; i++) {
let start = DateTime.fromFormat(fuehrungszeiten[i].start, 'yyyyMMdd'); let start = moment(fuehrungszeiten[i].start);
start = start.plus({ hours: fuehrungszeiten[i].uhr }); start.add(fuehrungszeiten[i].uhr,'h')
fuehrungszeiten[i].start = start.toISO(); fuehrungszeiten[i].start = moment(start).format()
let kurz = checkGroupinBeos(beos, fuehrungszeiten[i]); let kurz = checkGroupinBeos(beos, fuehrungszeiten[i]);
if (kurz.k != "") { if (kurz.k != "") {
fuehrungszeiten[i].title += " " + kurz.k; fuehrungszeiten[i].title += " " + kurz.k;
@@ -434,16 +433,16 @@ document.addEventListener('DOMContentLoaded', async function () {
// Array mit den Feiertagen // Array mit den Feiertagen
async function getHolidays(start, end) { async function getHolidays(start, end) {
let data = []; let data = [];
let startyear = DateTime.fromJSDate(start).year; let startyear = moment(start).year();
let endyear = DateTime.fromJSDate(end).year; let endyear = moment(end).year();
let response = await fetch('https://feiertage-api.de/api/?jahr=' + startyear + '&nur_land=BW'); let response = await fetch('https://feiertage-api.de/api/?jahr=' + startyear + '&nur_land=BW');
let holidays = await response.json(); let holidays = await response.json();
for (const [k, v] of Object.entries(holidays)) { for (const [k, v] of Object.entries(holidays)) {
if(k == "Ostermontag") { if(k == "Ostermontag") {
data.push({start: DateTime.fromISO(v.datum).minus({ days: 1 }).toFormat('yyyy-MM-dd'), title: "Ostersonntag"}); data.push({start: moment(v.datum).subtract(1,'days').format("YYYY-MM-DD"), title: "Ostersonntag"});
} }
if(k == "Pfingstmontag") { if(k == "Pfingstmontag") {
data.push({start: DateTime.fromISO(v.datum).minus({ days: 1 }).toFormat('yyyy-MM-dd'), title: "Pfingstsonntag"}); data.push({start: moment(v.datum).subtract(1,'days').format("YYYY-MM-DD"), title: "Pfingstsonntag"});
} }
data.push({start: v.datum, title: k}); data.push({start: v.datum, title: k});
} }
@@ -463,20 +462,20 @@ document.addEventListener('DOMContentLoaded', async function () {
// Return: // Return:
// Array mit den Sonntagen // Array mit den Sonntagen
function getSundays(dt) { function getSundays(dt) {
let year = DateTime.fromJSDate(dt).year; let year = moment(dt).year();
const cm = DateTime.fromJSDate(dt).month; const cm = moment(dt).month()
if (DateTime.fromJSDate(dt).month == 12) { if (moment(dt).month() == 11) {
year += 1; year += 1;
} }
let data = []; let data = [];
for (let i = 1; i <= 12; i++) { for (let i = 1; i <= 12; i++) {
let d = DateTime.fromObject({ year: year, month: i, day: 1 }); let d = moment(year + '-' + i + '-01');
let w = d.weekday; let w = d.isoWeekday();
let dt = ''; let dt = ''
if (w == 7) { if (w == 7) {
dt = d.toFormat('yyyy-MM-dd'); dt = d.format('YYYY-MM-DD');
} else { } else {
dt = d.plus({ days: 7 - w }).toFormat('yyyy-MM-dd'); dt = d.add(7 - w, 'd').format('YYYY-MM-DD')
} }
data.push({start: dt + 'T11:00:00', uhr: 11, title: 'Sonnenführung' }) data.push({start: dt + 'T11:00:00', uhr: 11, title: 'Sonnenführung' })
} }
@@ -511,18 +510,17 @@ document.addEventListener('DOMContentLoaded', async function () {
// Informationen einer Regelführung für das Popup zusammenbauen // Informationen einer Regelführung für das Popup zusammenbauen
function getRegularInfo(entryInfo) { function getRegularInfo(entryInfo) {
let dt = DateTime.fromJSDate(entryInfo.start); let curDate = moment(entryInfo.start).format('YYYYMMDD');
let curDate = dt.toFormat('yyyyMMdd');
let besucher = entryInfo._def.extendedProps.count; let besucher = entryInfo._def.extendedProps.count;
if (besucher == null) { besucher = "0"} if (besucher == null) { besucher = "0"}
besucher = parseInt(besucher) besucher = parseInt(besucher)
let wtg = dt.weekday; let wtg = moment(entryInfo.start).isoWeekday();
let nbr = entryInfo.title.split(' '); let nbr = entryInfo.title.split(' ');
let str = `<h6>${weekdays[wtg - 1]}s-Team ${nbr[1]}</h6>`; let str = `<h6>${weekdays[wtg - 1]}s-Team ${nbr[1]}</h6>`;
str += `<div id="beonamen">${entryInfo._def.extendedProps.namen}</div>`; str += `<div id="beonamen">${entryInfo._def.extendedProps.namen}</div>`;
let btxt = besucher != 0 ? `<strong>${besucher}</strong> angemeldete Besucher` : 'Keine Anmeldungen'; let btxt = besucher != 0 ? `<strong>${besucher}</strong> angemeldete Besucher` : 'Keine Anmeldungen';
str += btxt; str += btxt;
str += `<br />Von ${dt.toFormat('HH:mm')} Uhr bis: ${dt.plus({ minutes: default_dauer }).toFormat('HH:mm')} Uhr`; str += `<br />Von ${moment(entryInfo.start).format("HH:mm")} Uhr bis: ${moment(entryInfo.start).add(default_dauer, 'm').format("HH:mm")} Uhr`;
return str; return str;
} }
@@ -531,7 +529,7 @@ document.addEventListener('DOMContentLoaded', async function () {
// Wird bei dem Popup und bei dem Ändern/löschen verwendent // Wird bei dem Popup und bei dem Ändern/löschen verwendent
function getFuehrungsInfo(entryInfo) { function getFuehrungsInfo(entryInfo) {
let str = entryInfo._def.extendedProps.description; let str = entryInfo._def.extendedProps.description;
str += `<br /><br />Start: ${DateTime.fromJSDate(entryInfo.start).toFormat('yyyy-MM-dd HH:mm')} Uhr <br />Ende: ${DateTime.fromJSDate(entryInfo.end).toFormat('yyyy-MM-dd HH:mm')} Uhr`; str += `<br /><br />Start: ${moment(entryInfo.start).format("YYYY-MM-DD HH:mm")} Uhr <br />Ende: ${moment(entryInfo.end).format("YYYY-MM-DD HH:mm")} Uhr`;
return str; return str;
} }

View File

@@ -1,17 +1,12 @@
// VersiosNummern und -Geschichte // VersiosNummern und -Geschichte
var VERSION="1.3.3"; var VERSION="1.3.2";
var VDATE="2025-12-01"; var VDATE="2024-09-20";
/* History /* History
Rev. Datum Entwickler Rev. Datum Entwickler
1.3.3 2025-12-01 rxf
- 'heute' anders eingefärbt
- PHP-Interface nun DB4js_all.php
- anstelle 'moment' nun 'luxon' für die DateTime-Sachen verwendet
1.3.2 2024-09-20 rxf 1.3.2 2024-09-20 rxf
- Sonnenführunge mit anzeigen - Sonnenführunge mit anzeigen