Aufgaben: Rueckmeldungen ("Aufgaben & Feedback")
Letzter offener Punkt aus dem Konzept, Seite 4: Ein Creator hat laut Rollenbeschreibung "Aufgaben & Feedback" -- die Aufgaben gab es, das Feedback nicht. Ohne diese Moeglichkeit endet jede Rueckfrage ausserhalb des Systems, in WhatsApp, und damit ausserhalb dessen, was spaeter noch nachvollziehbar ist. Neue Tabelle aufgaben_notizen. Wer die Aufgabe sehen darf, darf auch mitreden -- geprueft ueber DIESELBE Sichtbarkeitsregel wie fuer die Aufgabe selbst. Eine eigene Regel gibt es bewusst nicht: Zwei Regeln fuer dieselbe Sache laufen irgendwann auseinander, und die Aufgaben- sichtbarkeit ist die schwierigere von beiden (Creator sieht eigene, Scout die seiner betreuten Creator, Leitung alles). 404 statt 403, wenn die Aufgabe nicht sichtbar ist -- wer sie nicht sehen darf, soll nicht erfahren, dass es sie gibt. Die eigene Rueckmeldung darf jeder zuruecknehmen, fremde nur die Leitung. Eine Rueckmeldung ist keine Abstimmung: Wer sich vertippt hat, soll das nicht bei jemandem beantragen muessen. Der Knopf auf der Karte zeigt die ANZAHL, nicht nur ein Symbol -- so sieht man ohne Aufklappen, wo schon etwas besprochen wurde, und die Karte bleibt trotzdem ruhig. Aufgeklappt wird direkt an der Karte, nicht in einem Fenster: Man liest die Rueckmeldungen im Zusammenhang mit der Aufgabe, sonst fehlt beim Antworten die Haelfte. Geprueft: - Chef und Luna schreiben sich gegenseitig, beide sehen beides - Mika (fremder Creator) bekommt 404 beim Lesen UND beim Schreiben - ohne Anmeldung 401, fremde Herkunft 403, leerer Text abgewiesen - Luna kann Chefs Rueckmeldung nicht loeschen, ihre eigene schon - Chef kann alle loeschen - Zaehler auf der Karte stimmt, Handy ohne Ueberlauf, 0 Konsolenfehler
This commit is contained in:
@@ -91,7 +91,9 @@ aufgabenRouter.get("/workspace/api/aufgaben", (req, res) => {
|
||||
try {
|
||||
const { wo, werte } = sichtbar(req.person);
|
||||
const reihen = db().prepare(`
|
||||
SELECT ${SPALTEN} ${VERBUND}
|
||||
SELECT ${SPALTEN},
|
||||
(SELECT COUNT(*) FROM aufgaben_notizen n WHERE n.aufgabe_id = a.id) AS notizen
|
||||
${VERBUND}
|
||||
WHERE ${wo}
|
||||
ORDER BY
|
||||
CASE a.prioritaet WHEN 'hoch' THEN 0 WHEN 'mittel' THEN 1 ELSE 2 END,
|
||||
@@ -186,6 +188,93 @@ function pruefeFelder(körper, { neu }) {
|
||||
return { aus, fehler };
|
||||
}
|
||||
|
||||
/* ---------- Rueckmeldungen ("Aufgaben & Feedback") ------------------------
|
||||
Wer die Aufgabe sieht, darf mitreden. Geprueft wird das ueber dieselbe
|
||||
Sichtbarkeitsregel wie fuer die Aufgabe selbst -- eine zweite Regel
|
||||
waere eine zweite Stelle, an der es irgendwann auseinanderlaeuft.
|
||||
|
||||
404 statt 403, wenn die Aufgabe nicht sichtbar ist: Wer sie nicht
|
||||
sehen darf, soll auch nicht erfahren, dass es sie gibt. */
|
||||
|
||||
const NOTIZ_MAX = 2000;
|
||||
|
||||
function aufgabeSichtbar(person, id) {
|
||||
const { wo, werte } = sichtbar(person);
|
||||
return db().prepare(`SELECT a.id FROM aufgaben a WHERE ${wo} AND a.id = ?`).get(...werte, id);
|
||||
}
|
||||
|
||||
aufgabenRouter.get("/workspace/api/aufgaben/:id/notizen", (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
|
||||
if (!aufgabeSichtbar(req.person, id)) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
res.json({
|
||||
notizen: db().prepare(`
|
||||
SELECT n.id, n.text, n.erstellt, n.person_id, p.name AS von, p.rolle AS rolle
|
||||
FROM aufgaben_notizen n LEFT JOIN personen p ON p.id = n.person_id
|
||||
WHERE n.aufgabe_id = ? ORDER BY n.id`).all(id),
|
||||
ich: req.person.id,
|
||||
darf_alles_loeschen: istLeitung(req.person),
|
||||
});
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Notizen lesen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
aufgabenRouter.post("/workspace/api/aufgaben/:id/notizen", gleicheHerkunft, (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
|
||||
if (!aufgabeSichtbar(req.person, id)) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
const text = String(req.body?.text ?? "").trim().slice(0, NOTIZ_MAX);
|
||||
if (text.length < 2) return res.status(400).json({ fehler: "Schreib erst etwas." });
|
||||
|
||||
const { lastInsertRowid } = db().prepare(
|
||||
"INSERT INTO aufgaben_notizen (aufgabe_id, person_id, text, erstellt) VALUES (?,?,?,?)")
|
||||
.run(id, req.person.id, text, jetzt());
|
||||
|
||||
protokolliere("aufgabe_notiz", {
|
||||
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
|
||||
detail: `Aufgabe #${id}`.slice(0, 120),
|
||||
});
|
||||
res.status(201).json({ id: Number(lastInsertRowid) });
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Notiz schreiben:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
aufgabenRouter.delete("/workspace/api/notizen/:id", gleicheHerkunft, (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
|
||||
const notiz = db().prepare(
|
||||
"SELECT id, aufgabe_id, person_id FROM aufgaben_notizen WHERE id = ?").get(id);
|
||||
if (!notiz) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
if (!aufgabeSichtbar(req.person, notiz.aufgabe_id)) {
|
||||
return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
}
|
||||
/* Die eigene Rueckmeldung darf jeder zuruecknehmen, fremde nur die
|
||||
Leitung. Eine Rueckmeldung ist keine Abstimmung -- wer sich
|
||||
vertippt hat, soll das nicht bei jemandem beantragen muessen. */
|
||||
if (notiz.person_id !== req.person.id && !istLeitung(req.person)) {
|
||||
return res.status(403).json({ fehler: "Fremde Rückmeldungen löscht nur die Leitung." });
|
||||
}
|
||||
db().prepare("DELETE FROM aufgaben_notizen WHERE id = ?").run(id);
|
||||
protokolliere("aufgabe_notiz_geloescht", {
|
||||
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
|
||||
detail: `#${id} zu Aufgabe #${notiz.aufgabe_id}`.slice(0, 120),
|
||||
});
|
||||
res.json({ ok: true });
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Notiz löschen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
aufgabenRouter.post("/workspace/api/aufgaben", gleicheHerkunft, (req, res) => {
|
||||
try {
|
||||
const { aus, fehler } = pruefeFelder(req.body || {}, { neu: true });
|
||||
|
||||
@@ -259,6 +259,23 @@ export function db() {
|
||||
CREATE INDEX IF NOT EXISTS idx_aufgaben_status ON aufgaben (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_aufgaben_creator ON aufgaben (creator_id);
|
||||
|
||||
/* Rueckmeldungen zu einer Aufgabe (Konzept: "Aufgaben & Feedback").
|
||||
Ohne sie endet jede Rueckfrage ausserhalb des Systems -- in
|
||||
WhatsApp, und damit ausserhalb dessen, was spaeter noch
|
||||
nachvollziehbar ist.
|
||||
Wer die Aufgabe sehen darf, darf auch die Rueckmeldungen sehen
|
||||
und schreiben. Eine eigene Sichtbarkeitsregel gibt es bewusst
|
||||
NICHT: Zwei Regeln fuer dieselbe Sache laufen irgendwann
|
||||
auseinander. */
|
||||
CREATE TABLE IF NOT EXISTS aufgaben_notizen (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
aufgabe_id INTEGER NOT NULL REFERENCES aufgaben(id) ON DELETE CASCADE,
|
||||
person_id INTEGER REFERENCES personen(id) ON DELETE SET NULL,
|
||||
text TEXT NOT NULL,
|
||||
erstellt TEXT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_aufgaben_notizen ON aufgaben_notizen (aufgabe_id);
|
||||
|
||||
/* Creator-Profil (Onboarding aus dem Konzept). Eine Zeile je
|
||||
Creator, entsteht erst beim ersten Speichern.
|
||||
admin_notiz ist bewusst Teil dieser Tabelle, wird aber nur an
|
||||
|
||||
@@ -165,3 +165,70 @@
|
||||
.karte__stift { margin-left: auto; }
|
||||
.karte__kopf { display: flex; align-items: flex-start; gap: 8px; }
|
||||
.karte__kopf .karte__titel { flex: 1 1 auto; }
|
||||
|
||||
/* ===================================================================
|
||||
Rückmeldungen an einer Aufgabe ("Aufgaben & Feedback", Konzept).
|
||||
|
||||
Direkt an der Karte, nicht in einem Fenster: Man liest sie im
|
||||
Zusammenhang mit der Aufgabe -- sonst fehlt beim Antworten die
|
||||
Hälfte.
|
||||
=================================================================== */
|
||||
|
||||
.karte__rueck {
|
||||
display: inline-flex; align-items: center; gap: 7px;
|
||||
margin-top: 10px; padding: 6px 11px; cursor: pointer;
|
||||
background: transparent;
|
||||
border: 1px solid var(--rand); border-radius: 999px;
|
||||
color: var(--text-still); font: inherit; font-size: .76rem;
|
||||
transition: color .16s ease, border-color .16s ease, background .16s ease;
|
||||
}
|
||||
.karte__rueck:hover { color: var(--text); border-color: rgba(255, 255, 255, .24); }
|
||||
/* Wo schon etwas besprochen wurde, sieht man es ohne Aufklappen. */
|
||||
.karte__rueck[data-hat="ja"] {
|
||||
color: var(--akzent);
|
||||
border-color: rgba(63, 189, 245, .38);
|
||||
background: rgba(63, 189, 245, .08);
|
||||
}
|
||||
.karte__rueck[data-offen="ja"] { border-color: rgba(63, 189, 245, .6); color: #fff; }
|
||||
.karte__blase {
|
||||
width: 14px; height: 14px; flex: none;
|
||||
fill: none; stroke: currentColor; stroke-width: 1.7;
|
||||
stroke-linecap: round; stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.rueck {
|
||||
margin-top: 11px; padding-top: 11px;
|
||||
border-top: 1px solid var(--rand);
|
||||
}
|
||||
.rueck__liste { display: grid; gap: 8px; margin-bottom: 11px; }
|
||||
.rueck__eintrag {
|
||||
padding: 9px 12px;
|
||||
background: rgba(255, 255, 255, .035);
|
||||
border: 1px solid var(--rand); border-radius: var(--radius-klein);
|
||||
}
|
||||
.rueck__kopf { display: flex; align-items: baseline; gap: 8px; margin: 0 0 3px; }
|
||||
.rueck__wer { font-size: .79rem; font-weight: 650; color: var(--text); }
|
||||
.rueck__wann { font-size: .72rem; color: var(--text-still); }
|
||||
.rueck__weg {
|
||||
margin-left: auto; padding: 0 5px; cursor: pointer; line-height: 1;
|
||||
background: none; border: 0; color: var(--text-still); font-size: 1rem;
|
||||
}
|
||||
.rueck__weg:hover { color: #ffb4b9; }
|
||||
.rueck__text {
|
||||
margin: 0; font-size: .85rem; color: var(--text-leise);
|
||||
white-space: pre-wrap; line-height: 1.5;
|
||||
}
|
||||
|
||||
.rueck__form { display: grid; gap: 8px; justify-items: start; }
|
||||
.rueck__feld {
|
||||
width: 100%; padding: 9px 12px;
|
||||
background: rgba(255, 255, 255, .045);
|
||||
border: 1px solid var(--rand); border-radius: var(--radius-klein);
|
||||
color: var(--text); font: inherit; font-size: .86rem; resize: vertical;
|
||||
}
|
||||
.rueck__feld:focus {
|
||||
outline: none; border-color: rgba(63, 189, 245, .65);
|
||||
box-shadow: 0 0 0 3px rgba(63, 189, 245, .15);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) { .karte__rueck { transition: none; } }
|
||||
|
||||
@@ -49,6 +49,93 @@
|
||||
return `${t}.${m}.${j.slice(2)}`;
|
||||
}
|
||||
|
||||
/* ---------- Rückmeldungen ------------------------------------------------
|
||||
Direkt an der Karte, nicht in einem Fenster: Man liest sie im
|
||||
Zusammenhang mit der Aufgabe, sonst fehlt beim Antworten die Hälfte. */
|
||||
|
||||
const zeitpunkt = (iso) => {
|
||||
if (!iso) return '';
|
||||
const d = new Date(iso);
|
||||
const p = (n) => String(n).padStart(2, '0');
|
||||
return `${p(d.getDate())}.${p(d.getMonth() + 1)}. · ${p(d.getHours())}:${p(d.getMinutes())}`;
|
||||
};
|
||||
|
||||
async function rueckmeldungen(karteEl, a, knopfEl) {
|
||||
const vorhanden = karteEl.querySelector('.rueck');
|
||||
if (vorhanden) { vorhanden.remove(); delete knopfEl.dataset.offen; return; }
|
||||
knopfEl.dataset.offen = 'ja';
|
||||
|
||||
const box = el('div', 'rueck');
|
||||
box.append(el('p', 'leise', 'Wird geladen …'));
|
||||
karteEl.append(box);
|
||||
|
||||
let daten;
|
||||
try {
|
||||
const antwort = await hole(`/workspace/api/aufgaben/${a.id}/notizen`);
|
||||
if (!antwort.ok) {
|
||||
box.textContent = '';
|
||||
box.append(el('p', 'fehler', 'Konnte nicht geladen werden.'));
|
||||
return;
|
||||
}
|
||||
daten = await antwort.json();
|
||||
} catch { return; }
|
||||
|
||||
box.textContent = '';
|
||||
const liste = el('div', 'rueck__liste');
|
||||
if (!daten.notizen.length) liste.append(el('p', 'leise', 'Noch nichts besprochen.'));
|
||||
for (const n of daten.notizen) {
|
||||
const z = el('div', 'rueck__eintrag');
|
||||
const kopf = el('p', 'rueck__kopf');
|
||||
kopf.append(el('span', 'rueck__wer', n.von || 'Unbekannt'));
|
||||
kopf.append(el('span', 'rueck__wann', zeitpunkt(n.erstellt)));
|
||||
/* Die eigene Rückmeldung darf jeder zurücknehmen, fremde nur die
|
||||
Leitung -- wer sich vertippt hat, soll das nicht beantragen
|
||||
müssen. */
|
||||
if (n.person_id === daten.ich || daten.darf_alles_loeschen) {
|
||||
const weg = el('button', 'rueck__weg', '×');
|
||||
weg.type = 'button';
|
||||
weg.title = 'Rückmeldung entfernen';
|
||||
weg.setAttribute('aria-label', 'Rückmeldung entfernen');
|
||||
weg.addEventListener('click', async () => {
|
||||
if (!confirm('Diese Rückmeldung entfernen?')) return;
|
||||
const r = await hole('/workspace/api/notizen/' + n.id, { method: 'DELETE' });
|
||||
if (!r.ok) { melde('Entfernen hat nicht geklappt.'); return; }
|
||||
await laden();
|
||||
});
|
||||
kopf.append(weg);
|
||||
}
|
||||
z.append(kopf, el('p', 'rueck__text', n.text));
|
||||
liste.append(z);
|
||||
}
|
||||
box.append(liste);
|
||||
|
||||
const form = el('form', 'rueck__form');
|
||||
const feld = el('textarea', 'rueck__feld');
|
||||
feld.rows = 2;
|
||||
feld.maxLength = 2000;
|
||||
feld.placeholder = 'Rückmeldung schreiben …';
|
||||
const senden = el('button', 'knopf knopf--klein', 'Abschicken');
|
||||
senden.type = 'submit';
|
||||
form.append(feld, senden);
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const text = feld.value.trim();
|
||||
if (text.length < 2) return;
|
||||
senden.disabled = true;
|
||||
try {
|
||||
const r = await hole(`/workspace/api/aufgaben/${a.id}/notizen`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text }),
|
||||
});
|
||||
if (!r.ok) { melde((await r.json().catch(() => ({}))).fehler || 'Ging nicht.'); return; }
|
||||
await laden();
|
||||
} catch { /* umgeleitet */ } finally { senden.disabled = false; }
|
||||
});
|
||||
box.append(form);
|
||||
feld.focus();
|
||||
}
|
||||
|
||||
function karte(a) {
|
||||
const k = el('article', 'karte');
|
||||
k.dataset.prio = a.prioritaet;
|
||||
@@ -80,6 +167,23 @@
|
||||
if (ZURUECK[a.status]) schritte.append(knopf('◀ zurück', a, ZURUECK[a.status]));
|
||||
if (WEITER[a.status]) schritte.append(knopf(beschriftung(a.status), a, WEITER[a.status]));
|
||||
if (schritte.childElementCount) k.append(schritte);
|
||||
|
||||
/* Rückmeldungen ("Aufgaben & Feedback" aus dem Konzept). Der Knopf
|
||||
zeigt gleich die Anzahl -- so sieht man ohne Aufklappen, wo etwas
|
||||
besprochen wurde. */
|
||||
const rueck = el('button', 'karte__rueck');
|
||||
rueck.type = 'button';
|
||||
rueck.dataset.hat = a.notizen ? 'ja' : 'nein';
|
||||
const blase = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
blase.setAttribute('viewBox', '0 0 24 24');
|
||||
blase.setAttribute('class', 'karte__blase');
|
||||
blase.setAttribute('aria-hidden', 'true');
|
||||
blase.innerHTML = '<path d="M20.4 12.4c0 3.8-3.8 6.9-8.4 6.9-1 0-2-.15-2.9-.42L4 20.4l1.6-3.6a6.6 6.6 0 0 1-2-4.4C3.6 8.6 7.4 5.5 12 5.5s8.4 3.1 8.4 6.9z"/>';
|
||||
rueck.append(blase, el('span', null, a.notizen
|
||||
? `${a.notizen} ${a.notizen === 1 ? 'Rückmeldung' : 'Rückmeldungen'}`
|
||||
: 'Rückmeldung schreiben'));
|
||||
rueck.addEventListener('click', () => rueckmeldungen(k, a, rueck));
|
||||
k.append(rueck);
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -134,8 +134,8 @@
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/aufgaben.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/aufgaben.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -98,8 +98,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/calls.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/calls.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -49,9 +49,9 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/ki.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/calls.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/ki.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/calls.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/dateien.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/dateien.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -88,8 +88,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/dateien.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/dateien.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
type="image/webp" media="(max-width: 899px)" />
|
||||
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="gate">
|
||||
@@ -143,6 +143,6 @@
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/gate.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/gate.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/kalender.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/kalender.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -94,8 +94,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kalender.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kalender.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/personen.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/personen.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -93,8 +93,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/personen.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/personen.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -127,8 +127,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/profil.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/profil.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/report.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/report.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -86,9 +86,9 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/ki.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/report.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/ki.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/report.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/scouting.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/scouting.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -124,8 +124,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/scouting.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/scouting.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -56,8 +56,8 @@
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/start.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/start.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/startcheck.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/startcheck.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -65,9 +65,9 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/ki.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/startcheck.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/ki.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/startcheck.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/wissen.css?v=202608311225" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608311235" />
|
||||
<link rel="stylesheet" href="assets/css/wissen.css?v=202608311235" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -170,8 +170,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wissen.js?v=202608311225" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608311235" defer></script>
|
||||
<script src="assets/js/wissen.js?v=202608311235" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user