screen1 + A5 + B6: „wer zuerst Zeit hat" gilt wieder, und Aufgaben entstehen dort, wo die Person steht
DREI SACHEN, EIN ZUSAMMENHANG.
--- screen1 --------------------------------------------------------
Filipe zu meinem eigenen Satz „wer zuerst Zeit hat — genau das geht ja
nicht mehr": „falls das nicht mehr geht mach das es geht wenn es wieder
geht ist alles gut."
Er hat recht, und ich hatte zu schnell aufgegeben. „Wer zuerst Zeit
hat" muss nicht heissen, dass man sich selbst bedient -- es kann
genauso heissen, dass die ERSTE BEWERBUNG zuerst drankommt. Damit gilt
beides: Die Leitung entscheidet (sein Wunsch von vorhin), und wer
schnell ist, hat den Vorteil (sein Wunsch von eben).
Die Bewerbungen werden jetzt nach EINGANG sortiert, nicht nach Namen
-- die Abfrage sortiert sonst alphabetisch, und dann haette nicht der
Schnelle den Vorteil, sondern Frida. Der Erste bekommt die Marke
„zuerst da" (nur bei mehr als einer -- sonst ist es keine Auskunft,
sondern Fuellwerk).
Geprueft mit Absicht gegen das Alphabet: Nele bewirbt sich zuerst und
steht vorn, obwohl Frida im Alphabet vor ihr kaeme.
--- B6: der Knopf auf dem Aufgabenbrett ----------------------------
Filipe: „dieser button kann da jetzt doch endlich verschwinden, auf
dieser seite sollen ja keine aufgaben mehr verteilt werden."
ER HAT DABEI AUF DEN TEAM-DOGI-BILDSCHIRM GESEHEN, und das ist der
Unterschied zwischen „weg damit" und „weg damit, aber gemessen":
Rolle/Haus aufgaben.html entwicklung.html darfAnlegen
manager/agentur ja NEIN ja
creator/agentur ja NEIN ja
scout/agentur ja NEIN ja
spicy/agentur ja NEIN ja
Haette ich den Knopf einfach entfernt, koennten vier Rollen gar keine
Aufgabe mehr anlegen. Der Server nennt deshalb den ORT, und er leitet
ihn aus den KACHELN der Person ab -- nicht aus dem Seitenrecht (dann
haette DogFather auf der Agenturadresse den Knopf verloren, denn
oeffnen darf er die Seite, nur hat er dort keine Kachel dorthin) und
schon gar nicht aus dem Haus.
--- A5: anlegen, wo die Person steht -------------------------------
Filipe: „dieser buttion da soll nicht einen zu der seite aufgaben
fuehren sondern da in dieser seite die aufgaben erstellen und vergeben
koennen. plus man soll die aufgaben hier in dieser seite auch sehen."
Der Knopf war ein Link auf `aufgaben.html?neu=1`. Jetzt oeffnet er ein
Formular an Ort und Stelle. DREI FELDER, NICHT ZWOELF: Wer hier steht,
hat die Person schon gewaehlt; was fehlt, ist was, bis wann und ob
noch jemand mitmacht. Das grosse Formular auf dem Brett bleibt fuer
den Fall, dass man eine Aufgabe fuer irgendwen irgendwo anlegt -- zwei
vollstaendige Masken fuer dieselbe Sache waeren zwei Gelegenheiten,
eine davon zu vergessen.
Dazu die Aufgaben der gewaehlten Person, auf derselben Seite. Sie
kommen beim Auswaehlen und nicht auf Knopfdruck: Wer jemanden
durchgeht, will wissen, was bei ihm liegt.
Ohne Person ist der Knopf AUS statt weg -- sonst springt die Seite beim
Auswaehlen -- und der Satz daneben sagt, was fehlt.
Gemeldet wird, was der Server WIRKLICH gesetzt hat: `zuteilen` kann
eine Person weglassen (gesperrter Zugang). Wer das verschweigt, laesst
jemanden im Glauben, er habe drei Leute eingetragen.
--- EIN FUND AUF DEM EIGENEN BILDSCHIRMFOTO ------------------------
Die Bestaetigung „Clips vom Samstag schneiden steht jetzt bei Rieke."
stand in WARNROT -- `melde` schreibt immer in denselben Absatz, und
der heisst `.fehler`. Nicht schlimm und genau deshalb heimtueckisch:
Wer Bestaetigungen in Rot liest, sucht den Fehler, und wer sich daran
gewoehnt, ueberliest die echte Warnung. `melde` kennt jetzt eine gute
Nachricht; die Vorgabe bleibt „Fehler", damit die neun vorhandenen
Aufrufe nicht stillschweigend umgefaerbt werden.
GEPRUEFT
pruef-bewerbung-aufgaben 84/0 (von 66) -- neu: die Reihenfolge nach
Eingang mit Gegenprobe gegen das Alphabet, und ein Abschnitt, der A5
und B6 am echten Bildschirm durchspielt (Knopf weg auf dem Brett, kein
Link mehr auf der Entwicklungsseite, Formular oeffnet dort, Aufgabe
steht sofort in der Liste darunter UND wirklich in der Liste des
Servers, Bestaetigung als gute Nachricht gekennzeichnet).
Gruen: pruef-entwicklung, pruef-aufgabenbrett, pruef-css-klassen,
pruef-formulare, pruef-struktur.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -1257,6 +1257,20 @@
|
||||
border-top: 1px solid color-mix(in srgb, var(--rand) 70%, transparent);
|
||||
}
|
||||
.z-bewerbung__name { font-weight: 600; font-size: .88rem; }
|
||||
/* „Zuerst da" — die Auskunft, dass sich diese Person als Erste
|
||||
gemeldet hat. Leise gesetzt: Sie ist ein Hinweis fuer die
|
||||
Entscheidung, keine Vorschrift. */
|
||||
.z-bewerbung__zuerst {
|
||||
padding: 2px 8px;
|
||||
border: 1px solid color-mix(in srgb, var(--k-gut) 45%, transparent);
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--k-gut) 12%, transparent);
|
||||
color: var(--k-gut);
|
||||
font-size: .7rem; font-weight: 600; letter-spacing: .02em;
|
||||
}
|
||||
@media (forced-colors: active) {
|
||||
.z-bewerbung__zuerst { border: 1px solid CanvasText; }
|
||||
}
|
||||
/* Die Worte der Person duerfen die Knoepfe verdraengen, nicht
|
||||
umgekehrt: `flex: 1 1 100%` auf schmalen Schirmen kaeme zu frueh,
|
||||
`min-width` laesst sie erst umbrechen, wenn es eng wird. */
|
||||
|
||||
@@ -1592,6 +1592,145 @@
|
||||
color: var(--text-leise);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
DAS FORMULAR IM BAND (22.09.2026)
|
||||
---------------------------------------------------------------------
|
||||
Filipe: „dieser buttion da soll nicht einen zu der seite aufgaben
|
||||
fuehren sondern da in dieser seite die aufgaben erstellen und
|
||||
vergeben koennen."
|
||||
|
||||
ES LIEGT IM BAND UND NICHT DARUNTER. Das Band ist eine Flex-Reihe
|
||||
(Text links, Knopf rechts); `flex-basis: 100%` setzt das Formular
|
||||
als ganze Zeile darunter, ohne einen zweiten Kasten aufzumachen.
|
||||
Zwei Kaesten untereinander saehen aus wie zwei Sachen -- es ist
|
||||
aber eine: der Knopf und das, was er oeffnet.
|
||||
--------------------------------------------------------------------- */
|
||||
.e-neu {
|
||||
flex: 1 1 100%;
|
||||
margin: 14px 0 0;
|
||||
padding: 14px 0 0;
|
||||
border-top: 1px solid color-mix(in srgb, var(--rand) 80%, transparent);
|
||||
}
|
||||
|
||||
.e-neu__zeile { margin-bottom: 12px; }
|
||||
|
||||
.e-neu input[type="text"],
|
||||
.e-neu input[type="date"],
|
||||
.e-neu textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 44px;
|
||||
padding: 9px 11px;
|
||||
border: 1px solid var(--rand-hell);
|
||||
border-radius: var(--radius-klein, 10px);
|
||||
background: color-mix(in srgb, var(--tinte) 90%, #ffffff 10%);
|
||||
color: var(--text);
|
||||
font: inherit;
|
||||
font-size: .92rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.e-neu textarea { resize: vertical; }
|
||||
|
||||
/* Das Kalendersymbol kommt vom Browser und ist dunkel -- auf dunklem
|
||||
Grund unsichtbar. */
|
||||
.e-neu input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
filter: invert(1);
|
||||
opacity: .62;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.e-neu__knoepfe {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
DIE AUFGABEN DER PERSON
|
||||
---------------------------------------------------------------------
|
||||
„plus man soll die aufgaben hier in dieser seite auch sehen."
|
||||
|
||||
EINE ZEILE JE AUFGABE, keine Karte. Karten haben auf dieser Seite
|
||||
schon die Menschen; noch eine Kartensorte daneben macht aus einer
|
||||
Uebersicht ein Mosaik. Eine Zeile liest sich von links nach rechts:
|
||||
was, wie weit, bis wann.
|
||||
--------------------------------------------------------------------- */
|
||||
/* Eine Bestaetigung ist gruen, eine Absage rot. Ohne diese Regel
|
||||
stand „steht jetzt bei Rieke" in Warnrot -- und wer Bestaetigungen
|
||||
in Rot liest, ueberliest irgendwann die echte Warnung. */
|
||||
.fehler[data-gut="ja"] { color: color-mix(in srgb, var(--k-gut) 85%, var(--text)); }
|
||||
|
||||
.e-aufgaben { margin: 0 0 22px; }
|
||||
|
||||
.e-aufgaben__satz {
|
||||
margin: 0 0 10px;
|
||||
font-size: .86rem;
|
||||
color: var(--text-leise);
|
||||
}
|
||||
|
||||
.e-aufgaben__liste { display: flex; flex-direction: column; gap: 6px; }
|
||||
|
||||
.e-aufgaben__leer {
|
||||
margin: 0;
|
||||
font-size: .88rem;
|
||||
line-height: 1.55;
|
||||
color: var(--text-leise);
|
||||
}
|
||||
|
||||
.e-aufgabe {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 44px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--rand);
|
||||
border-left: 3px solid var(--e-stand, var(--rand-hell));
|
||||
border-radius: var(--radius-klein, 10px);
|
||||
background: color-mix(in srgb, var(--flaeche) 90%, transparent);
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
transition: border-color var(--tempo, .18s) ease;
|
||||
}
|
||||
.e-aufgabe:hover { border-color: var(--rand-hell); }
|
||||
.e-aufgabe:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
|
||||
|
||||
/* DER STAND TRAEGT DIE FARBE AM LINKEN RAND -- aber nie NUR die
|
||||
Farbe: Das Wort steht daneben. Ein Zustand, der allein an der Farbe
|
||||
haengt, ist fuer jeden verloren, der Farben anders sieht. */
|
||||
.e-aufgabe[data-status="offen"] { --e-stand: var(--k-mittel); }
|
||||
.e-aufgabe[data-status="arbeit"] { --e-stand: var(--akzent); }
|
||||
.e-aufgabe[data-status="review"] { --e-stand: var(--violett); }
|
||||
.e-aufgabe[data-status="erledigt"] { --e-stand: var(--k-gut); }
|
||||
.e-aufgabe[data-status="abgebrochen"] { --e-stand: var(--k-neutral); }
|
||||
|
||||
.e-aufgabe__titel { flex: 1 1 14rem; min-width: 0; font-size: .9rem; font-weight: 600; }
|
||||
.e-aufgabe__stand {
|
||||
padding: 2px 9px;
|
||||
border: 1px solid color-mix(in srgb, var(--e-stand) 45%, transparent);
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--e-stand) 12%, transparent);
|
||||
color: var(--e-stand);
|
||||
font-size: .72rem; font-weight: 600;
|
||||
}
|
||||
.e-aufgabe__frist { font-size: .78rem; color: var(--text-leise); }
|
||||
|
||||
/* Was fertig ist, tritt zurueck -- es steht noch da, draengt sich aber
|
||||
nicht mehr vor das Offene. */
|
||||
.e-aufgabe[data-status="erledigt"] .e-aufgabe__titel,
|
||||
.e-aufgabe[data-status="abgebrochen"] .e-aufgabe__titel {
|
||||
font-weight: 400;
|
||||
color: var(--text-leise);
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.e-neu { border-top: 1px solid CanvasText; }
|
||||
.e-aufgabe { border: 1px solid CanvasText; }
|
||||
.e-aufgabe__stand { border: 1px solid CanvasText; }
|
||||
}
|
||||
|
||||
/* Der Knopf ist ein Link -- er sieht aus wie ein Knopf und muss am
|
||||
Finger auch eines sein. */
|
||||
.e-verteilen .knopf {
|
||||
|
||||
@@ -1087,6 +1087,21 @@
|
||||
hier in einer Datei, die jeder herunterlaedt -- und waere am Tag
|
||||
der naechsten Aenderung falsch. */
|
||||
function darfAnlegen() {
|
||||
/* WO ANGELEGT WIRD, ENTSCHEIDET DER SERVER (22.09.2026).
|
||||
|
||||
Filipe: „dieser button kann da jetzt doch endlich verschwinden,
|
||||
auf dieser seite sollen ja keine aufgaben mehr verteilt werden."
|
||||
|
||||
Er hat dabei auf den Team-Dogi-Bildschirm gesehen. Auf der
|
||||
Agenturadresse gibt es die Entwicklungsseite nicht -- dort waere
|
||||
der Knopf ersatzlos weg, und vier Rollen koennten keine Aufgabe
|
||||
mehr anlegen. Der Server sagt deshalb, WO der Ort ist; er leitet
|
||||
es aus den Kacheln der Person ab.
|
||||
|
||||
`?? "aufgaben"` ist die vorsichtige Seite: Antwortet ein alter
|
||||
Server ohne dieses Feld, bleibt der Knopf da. Ein Knopf zu viel
|
||||
ist ein Schoenheitsfehler, ein fehlender eine Sackgasse. */
|
||||
if ((ich?.aufgaben_anlegen_auf ?? 'aufgaben') !== 'aufgaben') return false;
|
||||
return ich?.darf_aufgaben_anlegen !== false;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,26 @@
|
||||
if (text !== undefined) n.textContent = text;
|
||||
return n;
|
||||
};
|
||||
const melde = (t) => { const f = $('fehler'); if (f) { f.textContent = t; f.hidden = !t; } };
|
||||
/* EINE GUTE NACHRICHT DARF NICHT AUSSEHEN WIE EIN FEHLER
|
||||
(22.09.2026). Auf dem ersten Bildschirmfoto der neuen
|
||||
Aufgabenanlage stand „Clips vom Samstag schneiden steht jetzt bei
|
||||
Rieke." in Warnrot -- weil `melde` immer in denselben Absatz
|
||||
schreibt und der `.fehler` heisst.
|
||||
|
||||
Es ist nicht schlimm und genau deshalb heimtueckisch: Wer eine
|
||||
Bestaetigung in Rot liest, sucht den Fehler. Und wer sich daran
|
||||
gewoehnt, ueberliest den echten.
|
||||
|
||||
Die Vorgabe bleibt „Fehler" -- alle neun bisherigen Aufrufe meinen
|
||||
das, und ein Wechsel per Vorgabe haette sie alle stillschweigend
|
||||
umgefaerbt. */
|
||||
const melde = (t, gut) => {
|
||||
const f = $('fehler');
|
||||
if (!f) return;
|
||||
f.textContent = t;
|
||||
f.hidden = !t;
|
||||
f.dataset.gut = gut ? 'ja' : 'nein';
|
||||
};
|
||||
|
||||
const datum = (iso) => {
|
||||
if (!iso) return '';
|
||||
@@ -332,19 +351,266 @@
|
||||
if (!darf) return;
|
||||
const knopf = $('verteilen-knopf');
|
||||
const satz = $('verteilen-satz');
|
||||
/* WER UND WIE HEISST ER -- fuer das Formular darunter. Es steht
|
||||
hier und nicht im Formular selbst: Die Auswahl geschieht
|
||||
oberhalb, und zwei Stellen, die sich dieselbe Person merken,
|
||||
laufen auseinander. */
|
||||
fuerPerson = personId || null;
|
||||
fuerName = name || null;
|
||||
|
||||
if (personId) {
|
||||
knopf.href = `aufgaben.html?neu=1&fuer=${encodeURIComponent(personId)}`;
|
||||
knopf.textContent = name ? `Aufgabe für ${name}` : 'Aufgabe anlegen';
|
||||
knopf.disabled = false;
|
||||
satz.textContent = name
|
||||
? `Die Aufgabe landet direkt bei ${name} — mit einer Meldung.`
|
||||
: 'Die Aufgabe landet direkt bei der gewählten Person.';
|
||||
? `Sie landet direkt bei ${name} — mit einer Meldung.`
|
||||
: 'Sie landet direkt bei der gewählten Person.';
|
||||
} else {
|
||||
knopf.href = 'aufgaben.html?neu=1';
|
||||
knopf.textContent = 'Aufgabe anlegen';
|
||||
/* OHNE PERSON GIBT ES NICHTS ZU VERTEILEN. Der Knopf bleibt
|
||||
sichtbar (sonst springt die Seite beim Auswaehlen), aber
|
||||
abgeschaltet -- und der Satz sagt, was fehlt. */
|
||||
knopf.disabled = true;
|
||||
satz.textContent = 'Wähl links jemanden aus — dann legst du die Aufgabe direkt für ihn an.';
|
||||
formularZu();
|
||||
}
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
AUFGABEN ANLEGEN -- HIER, NICHT AUF EINER ANDEREN SEITE (22.09.2026)
|
||||
=====================================================================
|
||||
Filipe: „dieser buttion da soll nicht einen zu der seite aufgaben
|
||||
fuehren sondern da in dieser seite die aufgaben erstellen und
|
||||
vergeben koennen. plus man soll die aufgaben hier in dieser seite
|
||||
auch sehen."
|
||||
|
||||
DREI FELDER, NICHT ZWOELF. Wer hier steht, hat die Person schon
|
||||
gewaehlt; was fehlt, ist was, bis wann und ob noch jemand
|
||||
mitmacht. Das grosse Formular auf dem Brett bleibt, wo es ist --
|
||||
fuer den Fall, dass man eine Aufgabe fuer irgendwen irgendwo
|
||||
anlegt.
|
||||
===================================================================== */
|
||||
let fuerPerson = null;
|
||||
let fuerName = null;
|
||||
let mehrLeute = [];
|
||||
let leute = [];
|
||||
|
||||
function formularZu() {
|
||||
const f = $('e-neu');
|
||||
if (!f) return;
|
||||
f.hidden = true;
|
||||
const auf = $('verteilen-knopf');
|
||||
if (auf) auf.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
|
||||
function formularAuf() {
|
||||
const f = $('e-neu');
|
||||
if (!f || !fuerPerson) return;
|
||||
f.hidden = false;
|
||||
$('verteilen-knopf').setAttribute('aria-expanded', 'true');
|
||||
$('e-neu-fehler').textContent = '';
|
||||
/* DIE ANDEREN ZUR AUSWAHL -- ohne die schon gewaehlte Person.
|
||||
Sie zweimal anzubieten hiesse, man koennte sie doppelt
|
||||
eintragen; der Server wuerde es abfangen, aber die Frage
|
||||
haette gar nicht erst gestellt werden duerfen. */
|
||||
const ziel = $('e-mehr-leute');
|
||||
ziel.replaceChildren();
|
||||
mehrLeute = [];
|
||||
for (const p2 of (leute || [])) {
|
||||
if (String(p2.id) === String(fuerPerson)) continue;
|
||||
const zeile = document.createElement('label');
|
||||
zeile.className = 'z-wahl__zeile';
|
||||
const k = document.createElement('input');
|
||||
k.type = 'checkbox';
|
||||
k.value = String(p2.id);
|
||||
k.addEventListener('change', () => {
|
||||
mehrLeute = [...ziel.querySelectorAll('input:checked')].map((x) => Number(x.value));
|
||||
/* DIE ART FRAGT NUR, WER MEHR ALS EINEN EINTRAEGT. Bei einer
|
||||
Person gibt es nichts zu verteilen -- die Frage waere
|
||||
Fuellwerk. */
|
||||
$('e-mehr-art').hidden = mehrLeute.length === 0;
|
||||
});
|
||||
const t = document.createElement('span');
|
||||
t.textContent = p2.name || 'Jemand';
|
||||
zeile.append(k, t);
|
||||
ziel.append(zeile);
|
||||
}
|
||||
$('e-mehr-art').hidden = true;
|
||||
$('e-mehr').hidden = true;
|
||||
$('e-mehr-auf').setAttribute('aria-expanded', 'false');
|
||||
$('e-titel').focus();
|
||||
}
|
||||
|
||||
function aufgabenFormularAufbauen() {
|
||||
const auf = $('verteilen-knopf');
|
||||
if (!auf) return;
|
||||
auf.setAttribute('aria-expanded', 'false');
|
||||
auf.setAttribute('aria-controls', 'e-neu');
|
||||
auf.addEventListener('click', () => {
|
||||
if ($('e-neu').hidden) formularAuf(); else formularZu();
|
||||
});
|
||||
$('e-neu-abbrechen').addEventListener('click', () => {
|
||||
$('e-neu').reset();
|
||||
formularZu();
|
||||
});
|
||||
$('e-mehr-auf').addEventListener('click', () => {
|
||||
const k = $('e-mehr');
|
||||
k.hidden = !k.hidden;
|
||||
$('e-mehr-auf').setAttribute('aria-expanded', String(!k.hidden));
|
||||
$('e-mehr-auf').textContent = k.hidden
|
||||
? 'Noch jemanden dazunehmen' : 'Doch nur eine Person';
|
||||
if (k.hidden) {
|
||||
for (const x of $('e-mehr-leute').querySelectorAll('input:checked')) x.checked = false;
|
||||
mehrLeute = [];
|
||||
$('e-mehr-art').hidden = true;
|
||||
}
|
||||
});
|
||||
|
||||
$('e-neu').addEventListener('submit', async (ev) => {
|
||||
ev.preventDefault();
|
||||
const melder = $('e-neu-fehler');
|
||||
melder.textContent = '';
|
||||
const titel = $('e-titel').value.trim();
|
||||
if (titel.length < 2) {
|
||||
melder.textContent = 'Schreib kurz, was zu tun ist.';
|
||||
$('e-titel').focus();
|
||||
return;
|
||||
}
|
||||
if (!fuerPerson) {
|
||||
melder.textContent = 'Wähl links erst jemanden aus.';
|
||||
return;
|
||||
}
|
||||
const knopf = $('e-neu-speichern');
|
||||
knopf.disabled = true;
|
||||
try {
|
||||
const art = mehrLeute.length
|
||||
? ($('e-mehr-art').querySelector('input[name="e-verteilart"]:checked')?.value || 'mehrere')
|
||||
: 'einzeln';
|
||||
const a = await fetch('/workspace/api/aufgaben', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
titel,
|
||||
beschreibung: $('e-text').value.trim() || null,
|
||||
frist: $('e-frist').value || null,
|
||||
/* DIE GEWAEHLTE PERSON STEHT VORN. `zuteilen` leitet die
|
||||
Art ab; bei einer Person wird daraus „einzeln", und
|
||||
genau das ist gemeint. */
|
||||
zuteilung: [Number(fuerPerson), ...mehrLeute],
|
||||
verteilart: art,
|
||||
}),
|
||||
});
|
||||
const r = await a.json().catch(() => ({}));
|
||||
if (!a.ok) {
|
||||
melder.textContent = window.sagWas?.(r.fehler, 'Ging nicht.') || 'Ging nicht.';
|
||||
knopf.disabled = false;
|
||||
return;
|
||||
}
|
||||
/* WAS DER SERVER WIRKLICH GESETZT HAT, nicht was ich wollte.
|
||||
`zuteilen` kann eine Person weglassen (gesperrter Zugang)
|
||||
oder die Art aendern -- wer das verschweigt, laesst jemanden
|
||||
in dem Glauben, er habe drei Leute eingetragen. */
|
||||
const gesetzt = r?.zuteilung?.gesetzt;
|
||||
const fehlt = Array.isArray(gesetzt)
|
||||
? [Number(fuerPerson), ...mehrLeute].filter((x) => !gesetzt.includes(x)).length
|
||||
: 0;
|
||||
$('e-neu').reset();
|
||||
mehrLeute = [];
|
||||
formularZu();
|
||||
melde(fehlt
|
||||
? `Angelegt — aber ${fehlt} Person(en) konnten nicht eingetragen werden.`
|
||||
: `„${titel}" steht jetzt bei ${fuerName || 'ihm'}.`, !fehlt);
|
||||
await aufgabenZeigen(fuerPerson, fuerName);
|
||||
} catch {
|
||||
melder.textContent = 'Das hat gerade nicht geklappt. Versuch es noch einmal.';
|
||||
knopf.disabled = false;
|
||||
} finally {
|
||||
knopf.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
UND DIE AUFGABEN DIESER PERSON, AUF DERSELBEN SEITE
|
||||
---------------------------------------------------------------------
|
||||
„plus man soll die aufgaben hier in dieser seite auch sehen."
|
||||
|
||||
GEFILTERT WIRD IM BROWSER, nicht mit einem eigenen Weg im Server:
|
||||
Die Liste, die er ohnehin schickt, enthaelt die Zuteilung je
|
||||
Aufgabe. Ein zweiter Weg waere eine zweite Rechnung fuer dieselbe
|
||||
Frage -- und die Sichtbarkeitsregel muesste dort noch einmal
|
||||
stehen.
|
||||
--------------------------------------------------------------------- */
|
||||
async function aufgabenZeigen(personId, name) {
|
||||
const block = $('e-aufgaben-block');
|
||||
if (!block) return;
|
||||
if (!personId) { block.hidden = true; return; }
|
||||
try {
|
||||
const a = await fetch('/workspace/api/aufgaben', { credentials: 'same-origin' });
|
||||
if (!a.ok) { block.hidden = true; return; }
|
||||
const roh = await a.json();
|
||||
const alle = Array.isArray(roh) ? roh : (roh?.aufgaben || []);
|
||||
const nr = Number(personId);
|
||||
const meine = alle.filter((x) => Number(x.verantwortlich_id) === nr
|
||||
|| (x.zuteilung || []).some((z) => Number(z.person_id) === nr
|
||||
&& z.zustand !== 'abgelehnt'));
|
||||
|
||||
block.hidden = false;
|
||||
$('e-aufgaben-titel').textContent = name ? `Aufgaben von ${name}` : 'Ihre Aufgaben';
|
||||
|
||||
const offen = meine.filter((x) => x.status !== 'erledigt' && x.status !== 'abgebrochen');
|
||||
$('e-aufgaben-satz').textContent = meine.length
|
||||
? `${offen.length} offen, ${meine.length} insgesamt.`
|
||||
: '';
|
||||
|
||||
const liste = $('e-aufgaben-liste');
|
||||
liste.replaceChildren();
|
||||
if (!meine.length) {
|
||||
const p2 = document.createElement('p');
|
||||
p2.className = 'e-aufgaben__leer';
|
||||
p2.textContent = name
|
||||
? `${name} hat gerade keine Aufgabe. Leg oben eine an, wenn etwas ansteht.`
|
||||
: 'Gerade keine Aufgabe.';
|
||||
liste.append(p2);
|
||||
return;
|
||||
}
|
||||
/* OFFENE ZUERST. Was erledigt ist, interessiert danach -- und
|
||||
eine Liste nach Anlegedatum haette die wichtigste Zeile
|
||||
irgendwo in der Mitte. */
|
||||
const sortiert = [...meine].sort((x, y) => {
|
||||
const fertig = (z) => (z.status === 'erledigt' || z.status === 'abgebrochen' ? 1 : 0);
|
||||
return fertig(x) - fertig(y)
|
||||
|| String(x.frist || '9999').localeCompare(String(y.frist || '9999'));
|
||||
});
|
||||
for (const x of sortiert) {
|
||||
const a2 = document.createElement('a');
|
||||
a2.className = 'e-aufgabe';
|
||||
a2.href = 'aufgaben.html#a' + x.id;
|
||||
a2.dataset.status = x.status || 'offen';
|
||||
const t = document.createElement('span');
|
||||
t.className = 'e-aufgabe__titel';
|
||||
t.textContent = x.titel;
|
||||
a2.append(t);
|
||||
const m = document.createElement('span');
|
||||
m.className = 'e-aufgabe__stand';
|
||||
m.textContent = STATUS_WORT[x.status] || x.status || 'offen';
|
||||
a2.append(m);
|
||||
if (x.frist) {
|
||||
const f = document.createElement('span');
|
||||
f.className = 'e-aufgabe__frist';
|
||||
f.textContent = 'bis ' + datum(x.frist);
|
||||
a2.append(f);
|
||||
}
|
||||
liste.append(a2);
|
||||
}
|
||||
} catch { block.hidden = true; }
|
||||
}
|
||||
|
||||
const STATUS_WORT = {
|
||||
offen: 'Offen', arbeit: 'In Arbeit', review: 'Zur Freigabe',
|
||||
erledigt: 'Erledigt', abgebrochen: 'Abgebrochen',
|
||||
};
|
||||
|
||||
async function karte(id, springen = false) {
|
||||
offen = id;
|
||||
/* WER IST GERADE OFFEN? Die Antwort gehoert auf die Kacheln, nicht
|
||||
@@ -356,7 +622,13 @@
|
||||
}
|
||||
{
|
||||
const k = document.querySelector(`#personen .e-person[data-person="${id}"]`);
|
||||
verteilBandZeigen(id, k ? (k.dataset.name || k.textContent.trim()) : null);
|
||||
const wieHeisst = k ? (k.dataset.name || k.textContent.trim()) : null;
|
||||
verteilBandZeigen(id, wieHeisst);
|
||||
/* UND IHRE AUFGABEN GLEICH MIT. „plus man soll die aufgaben
|
||||
hier in dieser seite auch sehen." Sie kommen beim Auswaehlen,
|
||||
nicht auf Knopfdruck: Wer jemanden durchgeht, will wissen,
|
||||
was bei ihm liegt -- das ist keine Zusatzfrage. */
|
||||
aufgabenZeigen(id, wieHeisst);
|
||||
}
|
||||
const ziel = $('karte');
|
||||
const vorherY = window.scrollY;
|
||||
@@ -860,8 +1132,13 @@
|
||||
stufen = lage.stufen;
|
||||
|
||||
if (lage.leitung) {
|
||||
/* DIE LEUTE FUER „NOCH JEMANDEN DAZUNEHMEN" kommen aus
|
||||
derselben Antwort wie die Kacheln. Ein eigener Abruf waere
|
||||
eine zweite Liste, die im Zweifel eine andere ist. */
|
||||
leute = lage.personen || [];
|
||||
/* Das Verteil-Band gehoert zur Leitungssicht -- ein Modi sieht
|
||||
hier nur sich selbst und verteilt nichts. */
|
||||
aufgabenFormularAufbauen();
|
||||
verteilBandZeigen(null, null);
|
||||
$('personen-block').hidden = false;
|
||||
const ziel = $('personen');
|
||||
|
||||
@@ -174,9 +174,13 @@
|
||||
|
||||
Er sagt deshalb jedem, was FUER IHN gilt. */
|
||||
var angeboten = zu.filter(function (z) { return z.zustand !== 'abgelehnt'; }).length;
|
||||
/* „WER ZUERST ZEIT HAT" GILT WIEDER -- nur zaehlt jetzt, wer
|
||||
sich zuerst bewirbt. Der Satz stand einen Nachmittag lang
|
||||
anders da („bewirb dich, wenn du Zeit hast"), und das war
|
||||
zwar wahr, aber kleiner als das, was gemeint war. */
|
||||
kasten.append(el('p', 'z-karte__zeile', darfEntscheiden
|
||||
? 'Frei für ' + angeboten + ' Leute — wer zuerst Zeit hat'
|
||||
: 'Frei für ' + angeboten + ' Leute — bewirb dich, wenn du Zeit hast'));
|
||||
: 'Frei für ' + angeboten + ' Leute — wer zuerst Zeit hat, bewirbt sich zuerst'));
|
||||
}
|
||||
|
||||
var wer = el('ul', 'z-wer');
|
||||
@@ -371,10 +375,21 @@
|
||||
? 'Eine Bewerbung wartet auf deine Antwort:'
|
||||
: bewerbungen.length + ' Bewerbungen warten auf deine Antwort:'));
|
||||
|
||||
bewerbungen.forEach(function (z) {
|
||||
bewerbungen.forEach(function (z, i) {
|
||||
var wem = z.person_name || 'Jemand';
|
||||
var reihe = el('div', 'z-bewerbung');
|
||||
reihe.append(el('span', 'z-bewerbung__name', wem));
|
||||
/* DER ERSTE WIRD BENANNT, nicht nur oben hingestellt. Eine
|
||||
Reihenfolge allein sieht man nicht an -- man haelt sie fuer
|
||||
Zufall oder Alphabet. Erst das Wort macht daraus eine
|
||||
Auskunft: Wer zuerst da war, steht als Erster da, und man
|
||||
sieht, dass das kein Zufall ist.
|
||||
|
||||
Nur bei mehr als einer: Bei einer einzigen Bewerbung ist
|
||||
„zuerst da" keine Auskunft, sondern Fuellwerk. */
|
||||
if (i === 0 && bewerbungen.length > 1) {
|
||||
reihe.append(el('span', 'z-bewerbung__zuerst', 'zuerst da'));
|
||||
}
|
||||
if (z.grund) reihe.append(el('span', 'z-bewerbung__wort', '„' + z.grund + '"'));
|
||||
|
||||
[['annehmen', 'Annehmen', 'knopf--klar'],
|
||||
|
||||
Reference in New Issue
Block a user