V0.1
This commit is contained in:
138
server/lib/mappers.js
Normal file
138
server/lib/mappers.js
Normal file
@@ -0,0 +1,138 @@
|
||||
export function parseJsonField(v) {
|
||||
if (v == null) return undefined;
|
||||
if (typeof v === 'object') return v;
|
||||
return JSON.parse(v);
|
||||
}
|
||||
|
||||
export function mapMachine(r) {
|
||||
const o = {
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
typ: r.typ,
|
||||
seriennummer: r.seriennummer,
|
||||
standort: r.standort,
|
||||
listStatus:
|
||||
r.list_status != null && String(r.list_status).trim() !== ''
|
||||
? String(r.list_status).trim()
|
||||
: '',
|
||||
createdAt: r.created_at,
|
||||
updatedAt: r.updated_at,
|
||||
};
|
||||
if (r.extras != null && String(r.extras).trim() !== '') {
|
||||
try {
|
||||
o.extras =
|
||||
typeof r.extras === 'string' ? JSON.parse(r.extras) : r.extras;
|
||||
} catch {
|
||||
o.extras = null;
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
export function mapTicket(r) {
|
||||
const machine_row = parseJsonField(r.machine_row);
|
||||
const t = {
|
||||
id: r.id,
|
||||
machineId: r.machine_id,
|
||||
title: r.title,
|
||||
description: r.description,
|
||||
status: r.status,
|
||||
priority: r.priority,
|
||||
slaDays: r.sla_days != null ? r.sla_days : null,
|
||||
slaAnchorAt: r.sla_anchor_at ?? null,
|
||||
dueAt: r.sla_due_at ?? null,
|
||||
isOverdue: Boolean(r.sla_is_overdue),
|
||||
createdAt: r.created_at,
|
||||
/** Letzte Änderung: neueres aus Ticket-Zeile oder letztem Event (für Anzeige „Aktualisiert“). */
|
||||
updatedAt: r.ticket_last_activity_at ?? r.updated_at,
|
||||
};
|
||||
if (machine_row) {
|
||||
t.machine = mapMachine(machine_row);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
function mapAttachmentRow(a, ticketId) {
|
||||
return {
|
||||
id: a.id,
|
||||
originalName: a.original_name,
|
||||
mimeType: a.mime_type ?? null,
|
||||
sizeBytes: a.size_bytes,
|
||||
createdAt: a.created_at,
|
||||
url: `/tickets/${ticketId}/attachments/${a.id}/file`,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapEvent(r, attachmentRows = []) {
|
||||
const list = Array.isArray(attachmentRows) ? attachmentRows : [];
|
||||
return {
|
||||
id: r.id,
|
||||
ticketId: r.ticket_id,
|
||||
type: r.type,
|
||||
description: r.description,
|
||||
createdAt: r.created_at,
|
||||
callbackNumber: r.callback_number ?? null,
|
||||
teamviewerId: r.teamviewer_id ?? null,
|
||||
articleNumber: r.article_number ?? null,
|
||||
remoteDurationSeconds:
|
||||
r.remote_duration_seconds != null ? r.remote_duration_seconds : null,
|
||||
teamviewerNotes:
|
||||
r.teamviewer_notes != null && String(r.teamviewer_notes).trim() !== ''
|
||||
? String(r.teamviewer_notes).trim()
|
||||
: null,
|
||||
attachments: list.map((a) => mapAttachmentRow(a, r.ticket_id)),
|
||||
};
|
||||
}
|
||||
|
||||
export function mapPublicUser(r) {
|
||||
return {
|
||||
id: r.id,
|
||||
username: r.username,
|
||||
role: r.role,
|
||||
active: Boolean(r.active),
|
||||
source: r.source,
|
||||
ldapDn: r.ldap_dn || null,
|
||||
createdAt: r.created_at,
|
||||
updatedAt: r.updated_at,
|
||||
};
|
||||
}
|
||||
|
||||
/** Spätester Start der Bearbeitungszeit: gespeicherter Anker oder letztes Nutzer-Event (ohne SYSTEM). */
|
||||
export const ticketSlaActivityAnchorExpr = `MAX(
|
||||
datetime(COALESCE(t.sla_anchor_at, t.created_at)),
|
||||
COALESCE(
|
||||
(SELECT MAX(datetime(e.created_at)) FROM events e
|
||||
WHERE e.ticket_id = t.id AND e.type IN ('NOTE','CALL','REMOTE','PART','ATTACHMENT')),
|
||||
datetime(COALESCE(t.sla_anchor_at, t.created_at))
|
||||
)
|
||||
)`;
|
||||
|
||||
export const ticketSlaDueExpr = `datetime((${ticketSlaActivityAnchorExpr}), '+' || CAST(COALESCE(t.sla_days, 2) AS TEXT) || ' days')`;
|
||||
|
||||
/** Spätester Zeitpunkt aus Ticket und Historie (alle Event-Typen). */
|
||||
export const ticketLastActivityExpr = `MAX(
|
||||
datetime(t.updated_at),
|
||||
COALESCE(
|
||||
(SELECT MAX(datetime(e.created_at)) FROM events e WHERE e.ticket_id = t.id),
|
||||
datetime(t.updated_at)
|
||||
)
|
||||
)`;
|
||||
|
||||
export const ticketJoinSelect = `
|
||||
SELECT t.*,
|
||||
${ticketLastActivityExpr} AS ticket_last_activity_at,
|
||||
${ticketSlaDueExpr} AS sla_due_at,
|
||||
(CASE WHEN t.status IN ('OPEN','WAITING') AND datetime('now') > ${ticketSlaDueExpr} THEN 1 ELSE 0 END) AS sla_is_overdue,
|
||||
json_object(
|
||||
'id', m.id,
|
||||
'name', m.name,
|
||||
'typ', m.typ,
|
||||
'seriennummer', m.seriennummer,
|
||||
'standort', m.standort,
|
||||
'list_status', m.list_status,
|
||||
'extras', m.extras,
|
||||
'created_at', m.created_at,
|
||||
'updated_at', m.updated_at
|
||||
) AS machine_row
|
||||
FROM tickets t
|
||||
JOIN machines m ON m.id = t.machine_id`;
|
||||
Reference in New Issue
Block a user