Dashboard-Reihenfolge, Drei-Punkte-Menü, Mehrrollen-Kürzel, Login-Rechte
- Meine Aufgaben: Projekte in der Reihenfolge der Projektliste, je Konto per Ziehen umsortierbar (users.dashboard_reihenfolge) - Projektliste: Öffnen/Löschen hinter einem "⋯"-Menü - Avatare je Person statt je Rolle; mehrere Rollen als senkrechte Farbstreifen; Titelleiste zieht Rollenänderungen sofort nach - Nach dem Anmelden vollständiges Konto über /whoami laden (Seitenleiste zeigte sonst erst nach Neuladen alle Einträge) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b7e0bd0d92
commit
a2266662ad
11 files changed
+358
-36
No files matched your search
@@ -87,6 +87,54 @@ function weekSortKey(label){
|
||||
// Persistente ID fuer eine Person aus dem Kuerzel, damit Anwesenheit und
|
||||
// Zuordnungen auch nach einem Neuladen stabil bleiben.
|
||||
// Parameter: name (String). Rückgabe: String wie 'p_ab'.
|
||||
// beteiligteJePerson: fasst die Zuordnungen eines Projekts ({person, role,
|
||||
// state}; state 1 = Haupt, 2 = Unterstützung) zu EINEM Eintrag je Person
|
||||
// zusammen — wer Planung und Projektleitung macht, erscheint im
|
||||
// Avatar-Stapel nur einmal (Eriks Wunsch). Die Farbe folgt der wichtigsten
|
||||
// Rolle (Haupt vor Unterstützung, dann Reihenfolge ROLES), der Tooltip nennt
|
||||
// alle. Rückgabe: [{person, role, state, title}] in der Reihenfolge des
|
||||
// ersten Auftretens.
|
||||
function beteiligteJePerson(eintraege){
|
||||
const jePerson = new Map();
|
||||
(eintraege || []).forEach(e => {
|
||||
if(!e || !e.person || !(e.state > 0)) return;
|
||||
const key = e.person.id;
|
||||
if(!jePerson.has(key)) jePerson.set(key, { person: e.person, rollen: [] });
|
||||
jePerson.get(key).rollen.push({ role: e.role, state: Number(e.state) });
|
||||
});
|
||||
const rang = r => (r.state === 1 ? 0 : 10) + Math.max(0, ROLES.indexOf(r.role));
|
||||
return Array.from(jePerson.values()).map(({ person, rollen }) => {
|
||||
const haupt = rollen.slice().sort((a, b) => rang(a) - rang(b))[0];
|
||||
const liste = rollen.slice().sort((a, b) => ROLES.indexOf(a.role) - ROLES.indexOf(b.role))
|
||||
.map(r => r.role + (r.state === 2 ? ' (Unterstützung)' : '')).join(', ');
|
||||
const sortiert = rollen.slice().sort((a, b) => ROLES.indexOf(a.role) - ROLES.indexOf(b.role));
|
||||
return { person, role: haupt.role, state: haupt.state, rollen: sortiert, title: (person.fullName || person.name) + ' · ' + liste };
|
||||
});
|
||||
}
|
||||
|
||||
// ROLLEN_FARBE: dieselben Farben wie .board-avatar.role-* in styles.css.
|
||||
const ROLLEN_FARBE = { 'Planung': 'var(--green)', 'Projektleitung': 'var(--red)', 'Bauüberwachung': 'var(--accent)' };
|
||||
|
||||
// beteiligtenAvatarHtml: Kürzel-Kreis eines Eintrags aus beteiligteJePerson().
|
||||
// Bei mehreren Rollen (Eriks Wunsch) ist der Kreis in Segmente geteilt — je
|
||||
// Rolle eines in ihrer Farbe. Parameter: b, klasse
|
||||
// (Rollen-Klasse, z. B. roleClass(b.role)). Rückgabe: HTML-String.
|
||||
function beteiligtenAvatarHtml(b, klasse){
|
||||
const rollen = (b.rollen || []).filter(r => ROLLEN_FARBE[r.role]);
|
||||
if(rollen.length < 2){
|
||||
return `<span class="board-avatar ${klasse} state-${b.state}" title="${esc(b.title)}">${esc(b.person.name)}</span>`;
|
||||
}
|
||||
const teil = 100 / rollen.length;
|
||||
const stopps = rollen.map((r, i) => {
|
||||
// Immer die volle Rollenfarbe — eine blassere Abstufung für
|
||||
// Unterstützung wurde im Dunkelmodus zu einem eigenen, dunklen Ton.
|
||||
// Ob Haupt oder Unterstützung, steht im Tooltip.
|
||||
const farbe = ROLLEN_FARBE[r.role];
|
||||
return `${farbe} ${(i * teil).toFixed(2)}% ${((i + 1) * teil).toFixed(2)}%`;
|
||||
}).join(', ');
|
||||
return `<span class="board-avatar ist-mehrfach" style="background-image: linear-gradient(to right, ${stopps})" title="${esc(b.title)}">${esc(b.person.name)}</span>`;
|
||||
}
|
||||
|
||||
function personIdForName(name){
|
||||
return 'p_' + String(name).trim().toLowerCase().replace(/[^a-z0-9]/g,'_');
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user