Benutzer, Ticketzuweißungen

This commit is contained in:
2026-03-23 03:12:08 +01:00
parent e75a2e5e20
commit 08391cdb6c
29 changed files with 592 additions and 111 deletions

View File

@@ -21,6 +21,17 @@ import {
const UUID =
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
function formatAssigneeLabel(u) {
if (!u) return 'Nicht zugewiesen';
const name = [u.firstName, u.lastName].filter(Boolean).join(' ').trim();
return name || u.username || u.id;
}
function assigneeOptionLabel(u) {
const name = [u.firstName, u.lastName].filter(Boolean).join(' ').trim();
return name ? `${name} (${u.username})` : u.username;
}
const loadingEl = document.getElementById('page-loading');
const badIdEl = document.getElementById('ticket-bad-id');
const errEl = document.getElementById('page-error');
@@ -65,6 +76,11 @@ function fillTicketView(ticket) {
} else {
mrow.hidden = true;
}
const assignLabel = document.getElementById('t-assign-label');
if (assignLabel) {
assignLabel.textContent = formatAssigneeLabel(ticket.assignedTo);
}
}
function fillEditForm(ticket) {
@@ -103,7 +119,7 @@ function showEditMode() {
panelEdit.hidden = false;
}
async function viewTicketDetail(id) {
async function viewTicketDetail(id, canEdit) {
const [ticket, events] = await Promise.all([
apiGet(`/tickets/${id}`),
apiGet(`/tickets/${id}/events`),
@@ -123,6 +139,72 @@ async function viewTicketDetail(id) {
sect2.hidden = true;
}
if (!canEdit) {
document.getElementById('btn-t-edit').hidden = true;
document.getElementById('panel-ticket-edit').hidden = true;
const assignSel = document.getElementById('t-assign-user');
const assignP = assignSel?.closest('p');
if (assignP) assignP.hidden = true;
const assignRo = document.getElementById('t-assign-readonly');
if (assignRo) assignRo.hidden = false;
const slaRd = document.getElementById('t-sla-days');
if (slaRd) slaRd.disabled = true;
const evForm = document.getElementById('form-ev');
const evCard = evForm?.closest('.card');
if (evCard) evCard.hidden = true;
sect2.hidden = true;
const pv = document.getElementById('panel-ticket-view');
if (pv) {
const hint = document.createElement('p');
hint.className = 'muted';
hint.textContent = 'Nur Lesen.';
pv.appendChild(hint);
}
return;
}
const assignSel = document.getElementById('t-assign-user');
const assignRo = document.getElementById('t-assign-readonly');
if (assignRo) assignRo.hidden = true;
if (assignSel) {
try {
const users = await apiGet('/assignable-users');
assignSel.innerHTML = '';
const optNone = document.createElement('option');
optNone.value = '';
optNone.textContent = '— nicht zugewiesen —';
assignSel.appendChild(optNone);
for (const u of users) {
const opt = document.createElement('option');
opt.value = u.id;
opt.textContent = assigneeOptionLabel(u);
assignSel.appendChild(opt);
}
assignSel.value = currentTicket.assignedTo?.id ?? '';
} catch (err) {
assignSel.innerHTML = '<option value="">— Fehler beim Laden —</option>';
if (isAuthRedirectError(err)) return;
window.alert(err.message || 'Benutzerliste konnte nicht geladen werden.');
}
assignSel.onchange = async () => {
const v = assignSel.value;
const assignedUserId = v === '' ? null : v;
try {
const updated = await apiPut(`/tickets/${id}`, { assignedUserId });
const evs = await apiGet(`/tickets/${id}/events`);
currentTicket = updated;
fillTicketView(updated);
fillEditForm(updated);
assignSel.value = updated.assignedTo?.id ?? '';
renderEvents(sortEventsChronologicalWithAttachmentsLast(evs));
} catch (err) {
assignSel.value = currentTicket.assignedTo?.id ?? '';
if (isAuthRedirectError(err)) return;
window.alert(err.message || 'Zuweisung konnte nicht gespeichert werden.');
}
};
}
const slaSel = document.getElementById('t-sla-days');
if (slaSel) {
slaSel.onchange = async () => {
@@ -259,6 +341,7 @@ async function viewTicketDetail(id) {
async function init() {
const st = await guard({ activeNav: 'tickets' });
if (!st) return;
const canEdit = st.user?.canEditCrm === true;
const id = new URLSearchParams(location.search).get('id');
if (!id || !UUID.test(id)) {
@@ -273,7 +356,7 @@ async function init() {
bindAttachmentPreview(document.body);
try {
await viewTicketDetail(id);
await viewTicketDetail(id, canEdit);
} catch (e) {
if (isAuthRedirectError(e)) return;
showError(e.message || 'Fehler');