Dateien nach "public" hochladen

This commit is contained in:
Honey committed 2025-11-15 13:48:37 +01:00
1 parent 9df0922824
commit 58ceca14b3
5 files changed
+678

No files matched your search

+150
View File
@@ -0,0 +1,150 @@
document.addEventListener('DOMContentLoaded', () => {
const ticketsBody = document.getElementById('tickets-body');
const closedTicketsBody = document.getElementById('closed-tickets-body');
const searchInput = document.getElementById('search-tickets');
const statusFilter = document.getElementById('status-filter');
const priorityFilter = document.getElementById('priority-filter');
const categoryFilter = document.getElementById('category-filter');
const statTotal = document.getElementById('total-tickets');
const statOpen = document.getElementById('open-tickets');
const statInProgress = document.getElementById('in-progress-tickets');
const statClosed = document.getElementById('closed-tickets');
const statTotalTime = document.getElementById('time-tickets'); // Neu: Gesamtzeit Anzeige
searchInput.addEventListener('input', refreshTickets);
statusFilter.addEventListener('change', refreshTickets);
priorityFilter.addEventListener('change', refreshTickets);
categoryFilter.addEventListener('change', refreshTickets);
// Helper: Status/Priority zu "Title-Case-With-Dash"
function toTitleCaseWithDash(str) {
return str
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join('-');
}
async function fetchTickets() {
try {
const res = await fetch('/api/tickets');
return await res.json();
} catch (err) {
console.error('Error fetching tickets:', err);
return [];
}
}
async function deleteTicket(id) {
try {
const res = await fetch(`/api/tickets/${id}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ actor: 'Admin' })
});
return await res.json();
} catch (err) {
console.error('Error deleting ticket:', err);
}
}
async function refreshTickets() {
const tickets = await fetchTickets();
renderTickets(tickets);
updateStats(tickets);
}
function renderTickets(tickets) {
const status = statusFilter.value;
const priority = priorityFilter.value;
const category = categoryFilter.value;
const searchTerm = searchInput.value.toLowerCase();
const filtered = tickets.filter(t =>
(status === 'all' || t.status === status) &&
(priority === 'all' || t.priority === priority) &&
(category === 'all' || t.category === category) &&
(t.title.toLowerCase().includes(searchTerm) ||
t.description.toLowerCase().includes(searchTerm) ||
t.requester.toLowerCase().includes(searchTerm))
).sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
const openRows = [];
const closedRows = [];
filtered.forEach(ticket => {
const shortTitle = ticket.title.length > 50 ? ticket.title.slice(0, 50) + '...' : ticket.title;
// Wandle Status und Priority korrekt in Klassen um
const statusClass = toTitleCaseWithDash(ticket.status || 'Unknown');
const priorityClass = toTitleCaseWithDash(ticket.priority || 'None');
const rowHTML = `
<tr>
<td>${ticket.id}</td>
<td class="ticket-title">${shortTitle}</td>
<td>${ticket.requester}</td>
<td>${ticket.category || '-'}</td>
<td><span class="status-badge status-${statusClass}">${ticket.status || 'Unknown'}</span></td>
<td><span class="priority-badge priority-${priorityClass}">${ticket.priority || 'None'}</span></td>
<td>${formatDate(ticket.created_at)}</td>
<td>${ticket.total_time} min</td>
<td class="table-actions">
<button class="table-btn view-btn" data-id="${ticket.id}"><i class="fas fa-eye"></i></button>
<button class="table-btn delete-btn" data-id="${ticket.id}"><i class="fas fa-trash-alt"></i></button>
</td>
</tr>`;
if (ticket.status === 'Closed') {
closedRows.push(rowHTML);
} else {
openRows.push(rowHTML);
}
});
ticketsBody.innerHTML = openRows.length
? openRows.join('')
: `<tr><td colspan="8" class="empty-table">No open tickets found</td></tr>`;
if (closedTicketsBody) {
closedTicketsBody.innerHTML = closedRows.length
? closedRows.join('')
: `<tr><td colspan="8" class="empty-table">No closed tickets</td></tr>`;
}
// Event listeners an Buttons hängen
[...document.querySelectorAll('.view-btn')].forEach(btn =>
btn.addEventListener('click', () => {
window.location.href = `/ticketview/ticket-view-admin.html?id=${btn.dataset.id}`;
})
);
[...document.querySelectorAll('.delete-btn')].forEach(btn =>
btn.addEventListener('click', () => {
if (confirm('Are you sure you want to delete this ticket?')) {
deleteTicket(btn.dataset.id).then(refreshTickets);
}
})
);
}
function updateStats(tickets) {
statTotal.textContent = tickets.length;
statOpen.textContent = tickets.filter(t => t.status === 'Open').length;
statInProgress.textContent = tickets.filter(t => t.status === 'In Progress').length;
statClosed.textContent = tickets.filter(t => t.status === 'Closed').length;
// Gesamtzeit aller Tickets summieren (total_time in Minuten)
const totalTime = tickets.reduce((sum, ticket) => sum + (ticket.total_time || 0), 0);
statTotalTime.textContent = `${totalTime} min`;
}
function formatDate(date) {
return new Date(date).toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric'
});
}
refreshTickets();
});