diff --git a/api.php b/api.php index 29cfd12..6449edd 100644 --- a/api.php +++ b/api.php @@ -5132,20 +5132,20 @@ switch ($action) { $ticketId = substr(uniqid(), -8) . bin2hex(random_bytes(2)); $now = date('Y-m-d H:i:s'); _dbExecute( - "INSERT INTO tickets (id, company_id, subject, from_email, from_name, status, type, priority, zammad_ticket_id, ticket_number, created, updated) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + "INSERT INTO tickets (id, company_id, subject, from_email, from_name, status, type, priority, zammad_ticket_id, zammad_group, source, ticket_number, created, updated) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [$ticketId, $companyId, $zt['title'] ?? '', $zt['customer'] ?? '', $zt['customer'] ?? '', - $status, $type, $priority, $zammadId, (int)($zt['number'] ?? 0), + $status, $type, $priority, $zammadId, $group, 'zammad', (int)($zt['number'] ?? 0), $zt['created_at'] ? date('Y-m-d H:i:s', strtotime($zt['created_at'])) : $now, $zt['updated_at'] ? date('Y-m-d H:i:s', strtotime($zt['updated_at'])) : $now] ); $created++; } else { $ticketId = $existing['id']; - // Päivitä status/priority + // Päivitä status/priority/group _dbExecute( - "UPDATE tickets SET status = ?, type = ?, priority = ?, subject = ?, updated = ? WHERE id = ?", - [$status, $type, $priority, $zt['title'] ?? '', date('Y-m-d H:i:s', strtotime($zt['updated_at'] ?? 'now')), $ticketId] + "UPDATE tickets SET status = ?, type = ?, priority = ?, subject = ?, zammad_group = ?, updated = ? WHERE id = ?", + [$status, $type, $priority, $zt['title'] ?? '', $group, date('Y-m-d H:i:s', strtotime($zt['updated_at'] ?? 'now')), $ticketId] ); $updated++; } diff --git a/script.js b/script.js index 5e1cb82..0d8e6cd 100644 --- a/script.js +++ b/script.js @@ -1350,11 +1350,15 @@ let ticketTypeLabels = { muu: 'Muu', }; +let ticketPage = 1; +const TICKETS_PER_PAGE = 100; + async function loadTickets() { try { // Hae kaikkien yritysten tiketit jos useampi yritys const allParam = availableCompanies.length > 1 ? '&all=1' : ''; tickets = await apiCall('tickets' + allParam); + ticketPage = 1; renderTickets(); } catch (e) { console.error(e); } } @@ -1367,9 +1371,15 @@ function renderTickets() { const showMine = document.getElementById('ticket-show-mine').checked; let filtered = tickets; - // Piilota piilotettujen postilaatikoiden tiketit + // Piilota piilotettujen postilaatikoiden ja Zammad-ryhmien tiketit if (currentHiddenMailboxes.length > 0) { - filtered = filtered.filter(t => !currentHiddenMailboxes.includes(String(t.mailbox_id)) && !currentHiddenMailboxes.includes(t.mailbox_id)); + filtered = filtered.filter(t => { + // Piilota mailbox-perusteisesti + if (t.mailbox_id && (currentHiddenMailboxes.includes(String(t.mailbox_id)) || currentHiddenMailboxes.includes(t.mailbox_id))) return false; + // Piilota Zammad-ryhmä-perusteisesti + if (t.source === 'zammad' && t.zammad_group && currentHiddenMailboxes.includes('zammad_group:' + t.zammad_group)) return false; + return true; + }); } // Suljetut näkyvät vain kun täppä on päällä @@ -1431,6 +1441,14 @@ function renderTickets() { const ttbody = document.getElementById('tickets-tbody'); const noTickets = document.getElementById('no-tickets'); + + // Paginointi + const totalFiltered = filtered.length; + const totalPages = Math.max(1, Math.ceil(totalFiltered / TICKETS_PER_PAGE)); + if (ticketPage > totalPages) ticketPage = totalPages; + const startIdx = (ticketPage - 1) * TICKETS_PER_PAGE; + const pageTickets = filtered.slice(startIdx, startIdx + TICKETS_PER_PAGE); + if (filtered.length === 0) { ttbody.innerHTML = ''; noTickets.style.display = 'block'; @@ -1439,7 +1457,7 @@ function renderTickets() { noTickets.style.display = 'none'; document.getElementById('tickets-table').style.display = 'table'; const multiCompany = availableCompanies.length > 1; - ttbody.innerHTML = filtered.map(t => { + ttbody.innerHTML = pageTickets.map(t => { const lastType = t.last_message_type === 'reply_out' ? '→' : (t.last_message_type === 'note' ? '📝' : '←'); const typeLabel = ticketTypeLabels[t.type] || 'Muu'; const rowClass = t.priority === 'urgent' ? 'ticket-row-urgent' : (t.priority === 'tärkeä' ? 'ticket-row-important' : (t.status === 'kasittelyssa' ? 'ticket-row-active' : '')); @@ -1479,15 +1497,63 @@ function renderTickets() { if (counts.kasittelyssa) parts.push(`${counts.kasittelyssa} käsittelyssä`); if (counts.odottaa) parts.push(`${counts.odottaa} odottaa`); document.getElementById('ticket-status-summary').textContent = parts.join(' · '); + + // Paginointipalkki + renderTicketPagination(totalFiltered, totalPages); } -document.getElementById('ticket-search-input').addEventListener('input', () => renderTickets()); -document.getElementById('ticket-status-filter').addEventListener('change', () => renderTickets()); -document.getElementById('ticket-type-filter').addEventListener('change', () => renderTickets()); -document.getElementById('ticket-tag-filter').addEventListener('input', () => renderTickets()); -document.getElementById('ticket-sort').addEventListener('change', () => renderTickets()); -document.getElementById('ticket-show-closed').addEventListener('change', () => renderTickets()); -document.getElementById('ticket-show-mine').addEventListener('change', () => renderTickets()); +function renderTicketPagination(totalFiltered, totalPages) { + let paginationEl = document.getElementById('ticket-pagination'); + if (!paginationEl) { + paginationEl = document.createElement('div'); + paginationEl.id = 'ticket-pagination'; + paginationEl.style.cssText = 'display:flex;align-items:center;justify-content:center;gap:0.5rem;padding:0.75rem 0;flex-wrap:wrap;'; + const table = document.getElementById('tickets-table'); + table.parentNode.insertBefore(paginationEl, table.nextSibling); + } + if (totalPages <= 1) { + paginationEl.innerHTML = totalFiltered > 0 ? `${totalFiltered} tikettiä` : ''; + return; + } + let html = ''; + // Edellinen-nappi + html += ``; + html += ``; + + // Sivunumerot + const maxShow = 5; + let startPage = Math.max(1, ticketPage - Math.floor(maxShow / 2)); + let endPage = Math.min(totalPages, startPage + maxShow - 1); + if (endPage - startPage < maxShow - 1) startPage = Math.max(1, endPage - maxShow + 1); + + if (startPage > 1) html += `...`; + for (let p = startPage; p <= endPage; p++) { + if (p === ticketPage) { + html += ``; + } else { + html += ``; + } + } + if (endPage < totalPages) html += `...`; + + // Seuraava-nappi + html += ``; + html += ``; + + // Näytetään sivuinfo + const startNum = (ticketPage - 1) * TICKETS_PER_PAGE + 1; + const endNum = Math.min(ticketPage * TICKETS_PER_PAGE, totalFiltered); + html += `${startNum}–${endNum} / ${totalFiltered}`; + + paginationEl.innerHTML = html; + +document.getElementById('ticket-search-input').addEventListener('input', () => { ticketPage = 1; renderTickets(); }); +document.getElementById('ticket-status-filter').addEventListener('change', () => { ticketPage = 1; renderTickets(); }); +document.getElementById('ticket-type-filter').addEventListener('change', () => { ticketPage = 1; renderTickets(); }); +document.getElementById('ticket-tag-filter').addEventListener('input', () => { ticketPage = 1; renderTickets(); }); +document.getElementById('ticket-sort').addEventListener('change', () => { ticketPage = 1; renderTickets(); }); +document.getElementById('ticket-show-closed').addEventListener('change', () => { ticketPage = 1; renderTickets(); }); +document.getElementById('ticket-show-mine').addEventListener('change', () => { ticketPage = 1; renderTickets(); }); document.getElementById('bulk-select-all').addEventListener('change', function() { const checkboxes = document.querySelectorAll('.ticket-checkbox'); checkboxes.forEach(cb => { @@ -1496,6 +1562,11 @@ document.getElementById('bulk-select-all').addEventListener('change', function() else bulkSelectedIds.delete(cb.dataset.ticketId); }); updateBulkToolbar(); + // Näytä montako valittu kaikista sivuilta + const allCheckbox = document.getElementById('bulk-select-all'); + if (bulkSelectedIds.size > checkboxes.length) { + allCheckbox.title = `${bulkSelectedIds.size} tikettiä valittu (myös muilta sivuilta)`; + } }); document.getElementById('tickets-tbody').addEventListener('click', (e) => { @@ -2268,13 +2339,30 @@ async function initTicketSettings() { ).join(''); // Postilaatikoiden näkyvyys — checkbox per postilaatikko - visContainer.innerHTML = mailboxes.map(mb => { + let visHtml = mailboxes.map(mb => { const isHidden = currentHiddenMailboxes.includes(String(mb.id)) || currentHiddenMailboxes.includes(mb.id); return ``; }).join(''); + + // Zammad-ryhmät näkyvyyteen (haetaan tiketeistä) + try { + const zammadGroups = [...new Set(tickets.filter(t => t.source === 'zammad' && t.zammad_group).map(t => t.zammad_group))].sort(); + if (zammadGroups.length > 0) { + visHtml += '
Virhe ladattaessa postilaatikoita.
'; }