Aufgaben-Vorlagen: vier Bereiche mal vier Stufen, 48 fertige Aufgaben
Filipe: "ich will dass du die vier klassen ueberall mit aufgaben perfektionnierst ... ich will dass die 4 kategorien ueberall perfekt angepasst sind, mit perfekt kategorien und aufgaben." WAS GEFEHLT HAT, NACHGEMESSEN Die Tabelle `aufgaben` kannte weder Bereich noch Stufe, und Aufgabenvorlagen gab es keine. Die Checkliste sagt, WAS sitzen muss -- sie sagt nicht, was jemand als Naechstes TUT. Zwischen "Ton ist der Grund Nummer eins" und einem Abend, an dem der Ton wirklich besser wird, liegt eine Aufgabe mit Frist und Verantwortlichem. Die musste bisher jemand von Hand tippen. WAS JETZT DASTEHT live 12 Aufgaben · 3 je Stufe content 12 Aufgaben · 3 je Stufe technik 12 Aufgaben · 3 je Stufe community 12 Aufgaben · 3 je Stufe zusammen 48 Drei je Feld und nicht zehn: Wer zehn Aufgaben bekommt, macht keine. Drei sind ein Abend, eine Woche, ein Monat -- und die Fristen sind entsprechend gestaffelt. Jede Aufgabe bringt ihre Frist als `tage` mit; eine Aufgabe ohne Frist ist ein Wunsch. Die Sachaussagen stammen aus derselben Recherche wie die Checklistenpunkte: Lautheit minus 20 bis minus 24 LUFS, Tonspur 160 kbit/s, Bitrate hoechstens 75 Prozent des Uploads, Ankuendigung 30 bis 60 Minuten vorher, Verweildauer ueber 15 Minuten, Eskalation in vier Stufen, Intro-Retention ab 70 Prozent. DER WEG BIS ZUR ECHTEN AUFGABE `/workspace/api/vorlagen` liefert sie aus, `/uebernehmen` legt sie an -- als Zeile in `aufgaben`, nicht als weiterer Eintrag in `eintraege`. Eine Aufgabe hat einen Verantwortlichen, eine Frist und einen Status, der sich bewegt; das ist etwas anderes als eine Notiz. Zwei Orte fuer dieselbe Sache waeren der Anfang davon, dass sie auseinanderlaufen. Ohne Creator wird abgelehnt statt herrenlos angelegt. Ein Creator legt sie immer fuer SICH an, auch wenn er jemand anderen angibt. AUF DER SEITE Ein Block ueber dem Aufgabenbrett: zwei Knopfreihen (Bereich, Stufe), drei Karten mit Titel, Erklaerung, Frist und einem Knopf. Die Knopfreihen benutzen `.stufenleiter` aus der Checkliste -- dieselbe Einteilung, dieselbe Darstellung. Eine zweite Optik fuer dieselben vier Bereiche waeren zwei Sachen zum Lernen statt einer. ZWEI EIGENE FEHLER, BEIDE VON PRUEFUNGEN GEFUNDEN 1. Ich hatte verlangt, dass die Frist mit der Stufe waechst. Die Pruefung schlug fehl: Profi 6,7 Tage gegen Fortgeschritten 7,4. Beim Nachsehen war die ERWARTUNG falsch. Eine Profi-Aufgabe ist meist eine Messung -- anspruchsvoll, aber an einem Abend erledigt; eine Fortgeschrittenen-Aufgabe wie "Saeulen anlegen und drei Wochen halten" braucht zwangslaeufig Wochen. Die Stufe sagt, was man KOENNEN muss, nicht wie lange es dauert. Geprueft wird jetzt, was wirklich gilt: keine Anfaengeraufgabe ueber fuenf Tage, keine Meisteraufgabe unter einer Woche. 2. Der Block war zu durchsichtig. pruef-buehne mass den Untergrund als rgb(84, 69, 70) -- das Buehnenfoto -- und die Ueberschrift kam auf 3,61:1 statt 4,5:1. Ein durchsichtiger Kasten hat keinen Untergrund, sondern den, der gerade dahinterliegt. Jetzt eine deckende Flaeche mit Weichzeichner: 5,21:1. GEPRUEFT Neu: server/pruef-aufgaben-vorlagen.mjs, 30 Pruefungen -- Vollstaendigkeit, der Weg bis zur Aufgabe auf dem Brett des Creators, und sechs Gegenproben (unbekannte Stufe, unbekannter Bereich, Nummer ohne Vorlage, ohne Creator, fremder Creator, und ein Creator, der jemand anderen angibt). Dazu ein Browserteil, der klickt statt nur zu zaehlen. Ausserdem gruen: pruef-aufgabenbrett, pruef-buehne, pruef-css-klassen, pruef-handy. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -841,5 +841,167 @@ Das laesst sich nicht rueckgaengig machen. Erledigte Aufgaben sollten normalerwe
|
||||
}
|
||||
|
||||
await laden();
|
||||
await vorlagenbrettZeigen();
|
||||
})();
|
||||
|
||||
/* =====================================================================
|
||||
AUFGABEN AUS DER VORLAGE
|
||||
|
||||
Vier Bereiche, vier Stufen, drei Aufgaben je Feld. Der Block ist
|
||||
bewusst KEINE zweite Aufgabenverwaltung: Er legt eine ganz normale
|
||||
Aufgabe an, mit Frist und Verantwortlichem, und verschwindet danach
|
||||
aus dem Weg. Alles Weitere macht das Brett darunter.
|
||||
|
||||
WARUM DIE BEIDEN REIHEN DIESELBEN KNOEPFE SIND WIE IN DER
|
||||
CHECKLISTE: Es sind dieselben vier Bereiche und dieselben vier
|
||||
Stufen. Zwei verschiedene Darstellungen fuer dieselbe Einteilung
|
||||
waeren zwei Sachen zum Lernen statt einer.
|
||||
|
||||
OHNE CREATOR KEINE AUFGABE. Ein Creator legt sie fuer sich an, ein
|
||||
Betreuer fuer den, den er oben gewaehlt hat. Ist keiner gewaehlt,
|
||||
steht das da -- statt eines Knopfes, der beim Druecken einen Fehler
|
||||
zeigt.
|
||||
===================================================================== */
|
||||
const BEREICHE_VORLAGE = [
|
||||
{ schluessel: 'live', name: 'LIVE-Analyse' },
|
||||
{ schluessel: 'content', name: 'Content-Ideen' },
|
||||
{ schluessel: 'technik', name: 'Technik' },
|
||||
{ schluessel: 'community', name: 'Community' },
|
||||
];
|
||||
const STUFEN_VORLAGE = [
|
||||
{ schluessel: 'anfaenger', name: 'Anfänger',
|
||||
hilfe: 'Was von Anfang an sitzen muss. Meist an einem Abend zu schaffen.' },
|
||||
{ schluessel: 'fort', name: 'Fortgeschritten',
|
||||
hilfe: 'Aus Zufall wird Routine. Braucht Wiederholung, also Wochen.' },
|
||||
{ schluessel: 'profi', name: 'Profi',
|
||||
hilfe: 'Gemessen statt geschätzt: ein Wert, ein Versuch, ein Beleg.' },
|
||||
{ schluessel: 'meister', name: 'Meister',
|
||||
hilfe: 'Was auch ohne dich weiterläuft — Vorlage, Vertretung, Ablage.' },
|
||||
];
|
||||
let vorlagen = null;
|
||||
let vBereich = 'live';
|
||||
let vStufe = 'anfaenger';
|
||||
|
||||
async function vorlagenbrettZeigen() {
|
||||
const ziel = $('vorlagenbrett');
|
||||
if (!ziel || !ich) return;
|
||||
if (!vorlagen) {
|
||||
try {
|
||||
const a = await hole('/workspace/api/vorlagen');
|
||||
if (!a.ok) return;
|
||||
vorlagen = (await a.json()).aufgaben || null;
|
||||
} catch { return; }
|
||||
}
|
||||
if (!vorlagen) return;
|
||||
ziel.hidden = false;
|
||||
ziel.textContent = '';
|
||||
|
||||
const kopf = el('div', 'vorlagenbrett__kopf');
|
||||
kopf.append(el('h2', 'feldschild', 'Aufgaben aus der Vorlage'));
|
||||
kopf.append(el('p', 'vorlagenbrett__unter',
|
||||
'Vier Bereiche, vier Stufen. Übernommen wird als ganz normale Aufgabe '
|
||||
+ '– mit Frist, veränderbar, auf dem Brett darunter.'));
|
||||
ziel.append(kopf);
|
||||
|
||||
/* Reihe 1: der Bereich. */
|
||||
const r1 = el('div', 'stufenleiter');
|
||||
r1.setAttribute('role', 'group');
|
||||
r1.setAttribute('aria-label', 'Bereich wählen');
|
||||
for (const b of BEREICHE_VORLAGE) {
|
||||
const k = el('button', 'stufenleiter__knopf');
|
||||
k.type = 'button';
|
||||
k.dataset.stufe = b.schluessel;
|
||||
k.setAttribute('aria-pressed', String(vBereich === b.schluessel));
|
||||
k.append(el('span', 'stufenleiter__name', b.name));
|
||||
k.addEventListener('click', () => { vBereich = b.schluessel; vorlagenbrettZeigen(); });
|
||||
r1.append(k);
|
||||
}
|
||||
ziel.append(r1);
|
||||
|
||||
/* Reihe 2: die Stufe, mit der Zahl der Aufgaben darin. */
|
||||
const r2 = el('div', 'stufenleiter');
|
||||
r2.setAttribute('role', 'group');
|
||||
r2.setAttribute('aria-label', 'Könnensstufe wählen');
|
||||
for (const st of STUFEN_VORLAGE) {
|
||||
const n = ((vorlagen[vBereich] || {})[st.schluessel] || []).length;
|
||||
if (!n) continue;
|
||||
const k = el('button', 'stufenleiter__knopf');
|
||||
k.type = 'button';
|
||||
k.dataset.stufe = st.schluessel;
|
||||
k.setAttribute('aria-pressed', String(vStufe === st.schluessel));
|
||||
k.title = st.hilfe;
|
||||
k.append(el('span', 'stufenleiter__name', st.name));
|
||||
k.append(el('span', 'stufenleiter__zahl', String(n)));
|
||||
k.addEventListener('click', () => { vStufe = st.schluessel; vorlagenbrettZeigen(); });
|
||||
r2.append(k);
|
||||
}
|
||||
ziel.append(r2);
|
||||
const hilfe = STUFEN_VORLAGE.find((x) => x.schluessel === vStufe)?.hilfe;
|
||||
if (hilfe) ziel.append(el('p', 'stufenleiter__hilfe', hilfe));
|
||||
|
||||
/* Für wen? */
|
||||
const fuer = ich.rolle === 'creator' ? ich.id : nurCreator;
|
||||
if (!fuer) {
|
||||
ziel.append(el('p', 'vorlagenbrett__hinweis',
|
||||
'Wähle oben einen Creator, dann lassen sich diese Aufgaben übernehmen.'));
|
||||
}
|
||||
|
||||
const liste = (vorlagen[vBereich] || {})[vStufe] || [];
|
||||
const box = el('div', 'vorlagenbrett__liste');
|
||||
for (const [nr, v] of liste.entries()) {
|
||||
const karte = el('div', 'vorlagenbrett__karte');
|
||||
karte.append(el('h3', 'vorlagenbrett__titel', v.titel));
|
||||
karte.append(el('p', 'vorlagenbrett__text', v.text));
|
||||
const fuss = el('div', 'vorlagenbrett__fuss');
|
||||
fuss.append(el('span', 'vorlagenbrett__frist',
|
||||
v.tage === 1 ? 'Frist: morgen' : `Frist: in ${v.tage} Tagen`));
|
||||
if (fuer) {
|
||||
const k = el('button', 'knopf knopf--klein', 'Übernehmen');
|
||||
k.type = 'button';
|
||||
k.addEventListener('click', () => uebernehmen(k, { art: 'aufgabe', nr }, fuer));
|
||||
fuss.append(k);
|
||||
}
|
||||
karte.append(fuss);
|
||||
box.append(karte);
|
||||
}
|
||||
ziel.append(box);
|
||||
|
||||
if (fuer && liste.length > 1) {
|
||||
const alle = el('button', 'abmelden', `Alle ${liste.length} übernehmen`);
|
||||
alle.type = 'button';
|
||||
alle.style.marginTop = '12px';
|
||||
alle.addEventListener('click', () => uebernehmen(alle, { art: 'aufgaben_alle' }, fuer));
|
||||
ziel.append(alle);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ein Weg fuer beide Knoepfe -- einzeln und alle. Zwei fast gleiche
|
||||
Funktionen waeren der sichere Weg dazu, dass die eine irgendwann
|
||||
anders reagiert als die andere. */
|
||||
async function uebernehmen(knopf, was, fuer) {
|
||||
knopf.disabled = true;
|
||||
const vorher = knopf.textContent;
|
||||
knopf.textContent = 'Wird übernommen …';
|
||||
try {
|
||||
const a = await hole('/workspace/api/vorlagen/uebernehmen', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...was, bereich: vBereich, stufe: vStufe, creator_id: fuer }),
|
||||
});
|
||||
if (!a.ok) {
|
||||
const f = await a.json().catch(() => ({}));
|
||||
melde(f.fehler || 'Das hat nicht geklappt.');
|
||||
knopf.disabled = false; knopf.textContent = vorher;
|
||||
return;
|
||||
}
|
||||
melde('');
|
||||
/* Erst das Brett neu laden, dann den Block -- so sieht man die
|
||||
neue Aufgabe sofort dort, wo sie ab jetzt lebt. */
|
||||
await laden();
|
||||
await vorlagenbrettZeigen();
|
||||
} catch {
|
||||
melde('Das hat nicht geklappt.');
|
||||
knopf.disabled = false; knopf.textContent = vorher;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user