Modis verteilen Aufgaben statt sie zu bekommen -- und Angebote zur Entscheidung
Die drei Beurteilungs-Bereiche liefen bisher in die falsche Richtung: Sie
bewerteten die Modis. Filipe: "die modis sind ja da um mir zu helfen."
Also umgedreht.
WAS SICH GEDREHT HAT
- Alle 101 Punkte sind jetzt Beobachtungen ueber den Stream, nicht
Pflichten des Modis ("Der Ton blieb verstaendlich" statt "Ton geprueft").
- Nur der Modi selbst drueckt auf seiner Liste. Wer sonst darauf zeigt,
bekommt 403 und den Weg zur Team-Lage -- bewerten wird hier niemand.
- "Verbessern" landet als Eingang bei DogFather. Ein Klick macht daraus
eine Aufgabe mit dem Satz des Modis im Text, oder eine Absage mit Grund.
Beides schreibt eine Nachricht zurueck, damit der Modi sieht: angekommen.
ANGEBOTE
Neuer Bereich, in dem Modis planen und vorschlagen: Nutzen und Aufwand
statt Bewertung und Dringlichkeit, dazu ein Feld "was DogFather danach
tun muss". Wird ein Angebot angenommen, entstehen zwei Aufgaben -- eine
beim Modi zum Umsetzen, eine bei DogFather aus genau diesem Feld.
GEMESSEN
pruef-modi-checkliste 59 Pruefungen, 0 Fehler (neu geschrieben)
pruef-rollen 245 statt 244 -- der Zuwachs ist die neue
Angebote-Kachel, alle 11 Modi-Kacheln kommen an
pruef-modi-ideen 30, pruef-modi-verborgen 75, pruef-bereiche-lesend: gruen
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -114,6 +114,165 @@
|
||||
return k;
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DER EINGANG -- was die Modis gemeldet haben.
|
||||
|
||||
Er steht OBEN, vor den Karten: Das ist das, was eine Antwort
|
||||
braucht. Die Zahlen darunter kann man sich ansehen; hier wartet
|
||||
jemand.
|
||||
|
||||
ZWEI ANTWORTEN, und beide kommen beim Modi an. Eine Meldung, auf
|
||||
die nichts folgt, sieht fuer ihn aus wie eine, die niemand gelesen
|
||||
hat -- und beim dritten Mal meldet er nichts mehr.
|
||||
===================================================================== */
|
||||
function eingangBauen(liste) {
|
||||
const k = el('section', 'tperson');
|
||||
k.append(el('p', 'feldschild', 'Rückmeldungen aus dem Team'));
|
||||
if (!liste.length) {
|
||||
k.append(el('p', 'tperson__zuletzt',
|
||||
'Nichts offen – auf alles, was gemeldet wurde, habt ihr geantwortet.'));
|
||||
return k;
|
||||
}
|
||||
for (const m of liste) {
|
||||
const zeile = el('div', 'tpipe');
|
||||
zeile.append(el('p', 'tperson__namen', m.titel));
|
||||
if (m.begruendung) zeile.append(el('p', 'tperson__unter', m.begruendung));
|
||||
zeile.append(el('span', 'tperson__zuletzt',
|
||||
`${m.von || 'jemand'} · ${(m.am || '').slice(0, 10)}`));
|
||||
|
||||
const knoepfe = el('div', 'tpipe__reihe');
|
||||
const melden = (t) => { melde(t); };
|
||||
|
||||
const ja = el('button', 'schritt', 'Daraus wird eine Aufgabe');
|
||||
ja.type = 'button';
|
||||
ja.addEventListener('click', async () => {
|
||||
ja.disabled = true;
|
||||
try {
|
||||
const a = await hole('/workspace/api/teamlage/behandeln', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
bereich: m.bereich, schluessel: m.schluessel,
|
||||
person_id: m.person_id, art: 'aufgabe',
|
||||
}),
|
||||
});
|
||||
if (!a.ok) {
|
||||
melden((await a.json().catch(() => ({}))).fehler || 'Das hat nicht geklappt.');
|
||||
ja.disabled = false; return;
|
||||
}
|
||||
melden('');
|
||||
await laden();
|
||||
} catch { ja.disabled = false; }
|
||||
});
|
||||
knoepfe.append(ja);
|
||||
|
||||
const nein = el('button', 'abmelden', 'Nicht nötig');
|
||||
nein.type = 'button';
|
||||
nein.addEventListener('click', async () => {
|
||||
/* EINE ABSAGE OHNE GRUND IST KEINE ANTWORT. Deshalb wird
|
||||
gefragt -- und ein leeres Feld bricht ab, statt still nichts
|
||||
zu tun. */
|
||||
const grund = window.prompt(
|
||||
`Warum machen wir das nicht?
|
||||
|
||||
„${m.titel}“`, '');
|
||||
if (grund === null) return;
|
||||
if (!grund.trim()) { melden('Ohne Grund bleibt die Meldung stehen.'); return; }
|
||||
nein.disabled = true;
|
||||
try {
|
||||
const a = await hole('/workspace/api/teamlage/behandeln', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
bereich: m.bereich, schluessel: m.schluessel,
|
||||
person_id: m.person_id, art: 'abgelehnt', grund: grund.trim(),
|
||||
}),
|
||||
});
|
||||
if (!a.ok) {
|
||||
melden((await a.json().catch(() => ({}))).fehler || 'Das hat nicht geklappt.');
|
||||
nein.disabled = false; return;
|
||||
}
|
||||
melden('');
|
||||
await laden();
|
||||
} catch { nein.disabled = false; }
|
||||
});
|
||||
knoepfe.append(nein);
|
||||
zeile.append(knoepfe);
|
||||
k.append(zeile);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DIE ANGEBOTE -- Vorschlaege, ueber die ihr entscheidet.
|
||||
|
||||
Sie stehen im selben Eingang wie die Rueckmeldungen: EIN Ort, an
|
||||
dem etwas auf eine Antwort wartet. Wer zwei Eingaenge hat, sieht
|
||||
irgendwann in den falschen.
|
||||
===================================================================== */
|
||||
const AUFWAND = { hoch: 'viel Aufwand', mittel: 'mittlerer Aufwand', niedrig: 'wenig Aufwand' };
|
||||
|
||||
async function entscheiden(knopf, koerper) {
|
||||
knopf.disabled = true;
|
||||
try {
|
||||
const a = await hole('/workspace/api/teamlage/angebot', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(koerper),
|
||||
});
|
||||
if (!a.ok) {
|
||||
melde((await a.json().catch(() => ({}))).fehler || 'Das hat nicht geklappt.');
|
||||
knopf.disabled = false; return;
|
||||
}
|
||||
const d = await a.json().catch(() => ({}));
|
||||
melde(d.aufgaben ? `${d.aufgaben} Aufgabe(n) angelegt.` : '');
|
||||
await laden();
|
||||
} catch { knopf.disabled = false; }
|
||||
}
|
||||
|
||||
function angeboteBauen(liste) {
|
||||
const k = el('section', 'tperson');
|
||||
k.append(el('p', 'feldschild', 'Angebote aus dem Team'));
|
||||
if (!liste.length) {
|
||||
k.append(el('p', 'tperson__zuletzt', 'Gerade liegt kein Vorschlag zur Entscheidung.'));
|
||||
return k;
|
||||
}
|
||||
for (const a of liste) {
|
||||
const zeile = el('div', 'tpipe');
|
||||
zeile.append(el('p', 'tperson__namen', a.titel));
|
||||
if (a.text) zeile.append(el('p', 'tperson__unter', a.text));
|
||||
/* WAS ES FUER DICH HEISST, steht direkt dabei -- sonst muss man
|
||||
die Entscheidung treffen, ohne den eigenen Teil zu kennen. */
|
||||
if (a.einsatz) {
|
||||
zeile.append(el('p', 'tperson__unter', `Dein Teil: ${a.einsatz}`));
|
||||
}
|
||||
zeile.append(el('span', 'tperson__zuletzt',
|
||||
`${a.von_name || 'jemand'} · Nutzen ${a.bewertung ?? '–'}/5 · `
|
||||
+ `${AUFWAND[a.dringlichkeit] || a.dringlichkeit}`));
|
||||
|
||||
const knoepfe = el('div', 'tpipe__reihe');
|
||||
const ja = el('button', 'schritt', 'Annehmen');
|
||||
ja.type = 'button';
|
||||
ja.addEventListener('click', () => entscheiden(ja, { id: a.id, art: 'angenommen' }));
|
||||
knoepfe.append(ja);
|
||||
|
||||
const nein = el('button', 'abmelden', 'Nicht umsetzen');
|
||||
nein.type = 'button';
|
||||
nein.addEventListener('click', () => {
|
||||
const grund = window.prompt(`Warum nicht?
|
||||
|
||||
„${a.titel}“`, '');
|
||||
if (grund === null) return;
|
||||
if (!grund.trim()) { melde('Ohne Grund bleibt das Angebot stehen.'); return; }
|
||||
entscheiden(nein, { id: a.id, art: 'abgelehnt', grund: grund.trim() });
|
||||
});
|
||||
knoepfe.append(nein);
|
||||
zeile.append(knoepfe);
|
||||
k.append(zeile);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
async function laden() {
|
||||
const ziel = $('lage');
|
||||
try {
|
||||
@@ -128,11 +287,15 @@
|
||||
s + Object.values(m.bereiche).reduce((x, b) => x + b.offen, 0), 0);
|
||||
/* Eine leere Seite ohne Erklaerung sieht aus wie ein Fehler --
|
||||
deshalb steht hier auch, was zu tun waere. */
|
||||
const wartend = (daten.eingang || []).length + (daten.angebote || []).length;
|
||||
$('kopf-unter').textContent = leute.length
|
||||
? `${leute.length} ${leute.length === 1 ? 'Person' : 'Personen'} · `
|
||||
+ `${offenGesamt} Punkte noch nicht besprochen`
|
||||
+ `${wartend} ${wartend === 1 ? 'Rückmeldung wartet' : 'Rückmeldungen warten'} · `
|
||||
+ `${offenGesamt} Punkte noch nicht beurteilt`
|
||||
: 'Noch niemand im Team. Zugänge legst du unter „Personen & Zugänge“ an.';
|
||||
|
||||
ziel.append(eingangBauen(daten.eingang || []));
|
||||
ziel.append(angeboteBauen(daten.angebote || []));
|
||||
for (const m of leute) ziel.append(karte(m));
|
||||
} catch { /* umgeleitet */ }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user