/** * Ticket List View * Full-featured ticket list with filters, sorting, batch actions, and pagination. */ const TicketListView = { currentPage: 1, perPage: 50, sortBy: 'create_time', sortDir: 'DESC', selectedIds: new Set(), searchTimeout: null, async render() { const container = document.getElementById('view-container'); container.innerHTML = '

Caricamento ticket...

'; try { // Fetch lookups for filter dropdowns await App.ensureLookups(); // Build query params const params = Filters.toQueryParams(); params.set('page', this.currentPage); params.set('per_page', this.perPage); params.set('sort_by', this.sortBy); params.set('sort_dir', this.sortDir); const searchInput = document.getElementById('global-search'); if (searchInput && searchInput.value.trim()) { params.set('search', searchInput.value.trim()); } const data = await App.api(`/api/tickets?${params.toString()}`); this.renderContent(container, data); this.bindEvents(data); } catch (err) { container.innerHTML = `
⚠️
Errore caricamento ticket
${App.escapeHtml(err.message)}
`; } }, renderContent(container, data) { const tickets = data.tickets || []; const { total, page, per_page, total_pages } = data; container.innerHTML = `
0 selezionati
Stato
Coda
Owner
${Filters.renderBar(App.lookups)}
${tickets.length > 0 ? tickets.map(t => ` `).join('') : ` `}
Titolo Stato Priorità Coda Owner Creato
${t.tn} ${App.escapeHtml(t.title || '(senza titolo)')} ${t.state_name} ${App.priorityIndex(t.priority_name)} ${t.queue_name} ${t.owner_first || ''} ${t.owner_last || ''} ${App.formatDateTime(t.create_time)}
📭
Nessun ticket trovato
Prova a cambiare i filtri o crea un nuovo ticket.
${total_pages > 1 ? ` ` : ` `} `; }, renderPageButtons(current, total) { const pages = []; const start = Math.max(1, current - 2); const end = Math.min(total, current + 2); for (let i = start; i <= end; i++) { pages.push(``); } return pages.join(''); }, bindEvents(data) { // Filter events Filters.bindEvents(() => { this.currentPage = 1; this.selectedIds.clear(); this.render(); }); // Sort events document.querySelectorAll('.ticket-table th.sortable').forEach(th => { th.addEventListener('click', () => { const sortKey = th.dataset.sort; if (this.sortBy === sortKey) { this.sortDir = this.sortDir === 'ASC' ? 'DESC' : 'ASC'; } else { this.sortBy = sortKey; this.sortDir = 'DESC'; } this.currentPage = 1; this.render(); }); }); // Row click → Toggle selection document.querySelectorAll('.ticket-table tbody tr[data-ticket-id]').forEach(row => { row.addEventListener('click', (e) => { // If click was on a link, let the browser perform navigation if (e.target.closest('.ticket-tn-link') || e.target.closest('.ticket-title-link')) { return; } const id = String(row.dataset.ticketId); if (this.selectedIds.has(id)) { this.selectedIds.delete(id); row.classList.remove('selected'); } else { this.selectedIds.add(id); row.classList.add('selected'); } this.updateBatchBar(); }); }); // Batch apply const batchApply = document.getElementById('batch-apply'); if (batchApply) { batchApply.addEventListener('click', () => this.applyBatch()); } // Batch select all visible const batchSelectAll = document.getElementById('batch-select-all'); if (batchSelectAll) { batchSelectAll.addEventListener('click', () => { document.querySelectorAll('.ticket-table tbody tr[data-ticket-id]').forEach(row => { const id = String(row.dataset.ticketId); this.selectedIds.add(id); row.classList.add('selected'); }); this.updateBatchBar(); }); } // Batch cancel const batchCancel = document.getElementById('batch-cancel'); if (batchCancel) { batchCancel.addEventListener('click', () => { this.selectedIds.clear(); document.querySelectorAll('.ticket-table tbody tr').forEach(tr => { tr.classList.remove('selected'); }); this.updateBatchBar(); }); } // Pagination document.querySelectorAll('.pagination-btn[data-page]').forEach(btn => { btn.addEventListener('click', () => { this.currentPage = parseInt(btn.dataset.page); this.selectedIds.clear(); this.render(); }); }); }, updateBatchBar() { const count = document.getElementById('batch-count'); if (count) { count.textContent = `${this.selectedIds.size} selezionat${this.selectedIds.size === 1 ? 'o' : 'i'}`; } }, async applyBatch() { if (this.selectedIds.size === 0) return; const updates = {}; const batchState = document.getElementById('batch-state')?.value; const batchQueue = document.getElementById('batch-queue')?.value; const batchOwner = document.getElementById('batch-owner')?.value; if (batchState) updates.ticket_state_id = parseInt(batchState); if (batchQueue) updates.queue_id = parseInt(batchQueue); if (batchOwner) updates.user_id = parseInt(batchOwner); if (Object.keys(updates).length === 0) { Toast.warning('Seleziona almeno un campo da modificare'); return; } try { const res = await App.api('/api/tickets/batch/update', { method: 'PATCH', body: JSON.stringify({ ticket_ids: Array.from(this.selectedIds), updates, }), }); Toast.success(res.message || `${this.selectedIds.size} ticket aggiornati`); this.selectedIds.clear(); this.render(); } catch (err) { Toast.error('Errore aggiornamento batch: ' + err.message); } }, };