fix: la ricerca fulltext parte solamente alla pressione del pulsante invio. feat: aggiunta possibilità di specificare una data per le nuove note.
This commit is contained in:
@@ -156,20 +156,8 @@ const App = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let timeout;
|
|
||||||
searchInput.addEventListener('input', () => {
|
searchInput.addEventListener('input', () => {
|
||||||
toggleClearBtn();
|
toggleClearBtn();
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(() => {
|
|
||||||
const hash = window.location.hash;
|
|
||||||
if (hash.startsWith('#/tickets') && !hash.includes('/new') && !hash.match(/#\/tickets\/\d+/)) {
|
|
||||||
TicketListView.currentPage = 1;
|
|
||||||
TicketListView.render();
|
|
||||||
} else {
|
|
||||||
// Navigate to ticket list with search
|
|
||||||
window.location.hash = '#/tickets';
|
|
||||||
}
|
|
||||||
}, 350);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
searchInput.addEventListener('keydown', (e) => {
|
searchInput.addEventListener('keydown', (e) => {
|
||||||
|
|||||||
@@ -263,6 +263,7 @@ const TicketDetailView = {
|
|||||||
<button type="button" class="btn btn-ghost btn-sm" id="btn-note-add-attachments" style="height:32px; padding: 4px 10px; font-size: 0.85rem; display: flex; align-items: center; gap: 4px;">📎 Allega file</button>
|
<button type="button" class="btn btn-ghost btn-sm" id="btn-note-add-attachments" style="height:32px; padding: 4px 10px; font-size: 0.85rem; display: flex; align-items: center; gap: 4px;">📎 Allega file</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; gap:var(--space-md); align-items:center;">
|
<div style="display:flex; gap:var(--space-md); align-items:center;">
|
||||||
|
<input type="datetime-local" class="note-subject-input" id="note-create-time" title="Data/ora nota (opzionale per retrodatazione)" style="width:185px; margin-bottom:0; height:32px; padding:4px 8px; font-size:0.82rem;" />
|
||||||
<input type="number" step="any" min="0" class="note-subject-input" id="note-time-units" placeholder="Tempo (minuti)" style="width:140px; margin-bottom:0; height:32px; padding:4px 10px; font-size:0.85rem;" />
|
<input type="number" step="any" min="0" class="note-subject-input" id="note-time-units" placeholder="Tempo (minuti)" style="width:140px; margin-bottom:0; height:32px; padding:4px 10px; font-size:0.85rem;" />
|
||||||
<button class="btn btn-ghost btn-sm" id="btn-open-email-compose" style="height:32px; display:flex; align-items:center; gap:var(--space-xs); border-color:var(--accent-secondary); color:var(--accent-secondary);"
|
<button class="btn btn-ghost btn-sm" id="btn-open-email-compose" style="height:32px; display:flex; align-items:center; gap:var(--space-xs); border-color:var(--accent-secondary); color:var(--accent-secondary);"
|
||||||
data-ticket-id="${ticket.id}" data-ticket-tn="${ticket.tn}" data-ticket-title="${App.escapeHtml(ticket.title)}" data-customer-email="${App.escapeHtml(ticket.customer_email || '')}">
|
data-ticket-id="${ticket.id}" data-ticket-tn="${ticket.tn}" data-ticket-title="${App.escapeHtml(ticket.title)}" data-customer-email="${App.escapeHtml(ticket.customer_email || '')}">
|
||||||
@@ -830,6 +831,7 @@ const TicketDetailView = {
|
|||||||
}
|
}
|
||||||
let subject = document.getElementById('note-subject').value.trim();
|
let subject = document.getElementById('note-subject').value.trim();
|
||||||
const time_unit = document.getElementById('note-time-units').value.trim();
|
const time_unit = document.getElementById('note-time-units').value.trim();
|
||||||
|
const note_create_time = document.getElementById('note-create-time')?.value;
|
||||||
|
|
||||||
// If body is empty but subject is provided, fill body with subject text
|
// If body is empty but subject is provided, fill body with subject text
|
||||||
if (!body && subject) {
|
if (!body && subject) {
|
||||||
@@ -869,7 +871,22 @@ const TicketDetailView = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.noteAttachments = []; // Clear attachments
|
this.noteAttachments = []; // Clear attachments
|
||||||
Toast.success(res.message || 'Nota aggiunta!');
|
|
||||||
|
if (note_create_time && res.article_id) {
|
||||||
|
try {
|
||||||
|
const formattedDate = note_create_time.replace('T', ' ');
|
||||||
|
await App.api(`/api/tickets/articles/${res.article_id}/retrodata-article`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ create_time: formattedDate })
|
||||||
|
});
|
||||||
|
Toast.success('Nota aggiunta e retrodatata!');
|
||||||
|
} catch (retErr) {
|
||||||
|
Toast.warning('Nota aggiunta, ma errore durante la retrodatazione: ' + retErr.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.success(res.message || 'Nota aggiunta!');
|
||||||
|
}
|
||||||
|
|
||||||
App.clearDraft(this.ticketId, 'note');
|
App.clearDraft(this.ticketId, 'note');
|
||||||
App.updateDailyTimer();
|
App.updateDailyTimer();
|
||||||
this.render(this.ticketId);
|
this.render(this.ticketId);
|
||||||
|
|||||||
@@ -106,13 +106,15 @@ const TicketListView = {
|
|||||||
${(App.lookups.users || []).map(u => `<option value="${u.id}">${u.first_name} ${u.last_name}</option>`).join('')}
|
${(App.lookups.users || []).map(u => `<option value="${u.id}">${u.first_name} ${u.last_name}</option>`).join('')}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-group" style="position:relative;">
|
${(App.lookups.types || []).length > 0 ? `
|
||||||
<span class="filter-label">Cliente</span>
|
<div class="filter-group">
|
||||||
<input type="text" class="form-input filter-select" id="batch-customer-search" placeholder="Cerca cliente..." autocomplete="off" style="width:160px; padding: 4px 8px; font-family: inherit; font-size: 0.85rem;" />
|
<span class="filter-label">Tipo</span>
|
||||||
<input type="hidden" id="batch-customer-user-id" />
|
<select class="filter-select" id="batch-type">
|
||||||
<input type="hidden" id="batch-customer-id" />
|
<option value="">—</option>
|
||||||
<div id="batch-customer-suggestions" class="autocomplete-suggestions" style="display:none; top: 100%; left: 0; width: 280px; z-index: 1001;"></div>
|
${App.lookups.types.map(t => `<option value="${t.id}">${t.name}</option>`).join('')}
|
||||||
</div>
|
</select>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
<button class="btn btn-primary btn-sm" id="batch-apply">Applica</button>
|
<button class="btn btn-primary btn-sm" id="batch-apply">Applica</button>
|
||||||
<button class="btn btn-primary btn-sm" id="batch-merge" disabled style="background: var(--accent-secondary); border-color: var(--accent-secondary); margin-left: 8px;">Unisci Selezionati</button>
|
<button class="btn btn-primary btn-sm" id="batch-merge" disabled style="background: var(--accent-secondary); border-color: var(--accent-secondary); margin-left: 8px;">Unisci Selezionati</button>
|
||||||
<button class="btn btn-primary btn-sm" id="batch-open-tabs" disabled style="background: var(--accent-primary); border-color: var(--accent-primary); margin-left: 8px;">Apri ticket in schede</button>
|
<button class="btn btn-primary btn-sm" id="batch-open-tabs" disabled style="background: var(--accent-primary); border-color: var(--accent-primary); margin-left: 8px;">Apri ticket in schede</button>
|
||||||
@@ -439,6 +441,8 @@ const TicketListView = {
|
|||||||
if (batchOwner) batchOwner.value = '';
|
if (batchOwner) batchOwner.value = '';
|
||||||
const batchResponsible = document.getElementById('batch-responsible');
|
const batchResponsible = document.getElementById('batch-responsible');
|
||||||
if (batchResponsible) batchResponsible.value = '';
|
if (batchResponsible) batchResponsible.value = '';
|
||||||
|
const batchType = document.getElementById('batch-type');
|
||||||
|
if (batchType) batchType.value = '';
|
||||||
|
|
||||||
this.updateBatchBar();
|
this.updateBatchBar();
|
||||||
});
|
});
|
||||||
@@ -620,6 +624,7 @@ const TicketListView = {
|
|||||||
const batchQueue = document.getElementById('batch-queue')?.value;
|
const batchQueue = document.getElementById('batch-queue')?.value;
|
||||||
const batchOwner = document.getElementById('batch-owner')?.value;
|
const batchOwner = document.getElementById('batch-owner')?.value;
|
||||||
const batchResponsible = document.getElementById('batch-responsible')?.value;
|
const batchResponsible = document.getElementById('batch-responsible')?.value;
|
||||||
|
const batchType = document.getElementById('batch-type')?.value;
|
||||||
const batchCustomerSearch = document.getElementById('batch-customer-search')?.value.trim();
|
const batchCustomerSearch = document.getElementById('batch-customer-search')?.value.trim();
|
||||||
let batchCustomerUserId = document.getElementById('batch-customer-user-id')?.value;
|
let batchCustomerUserId = document.getElementById('batch-customer-user-id')?.value;
|
||||||
let batchCustomerId = document.getElementById('batch-customer-id')?.value;
|
let batchCustomerId = document.getElementById('batch-customer-id')?.value;
|
||||||
@@ -633,6 +638,7 @@ const TicketListView = {
|
|||||||
|
|
||||||
if (batchState) updates.ticket_state_id = parseInt(batchState);
|
if (batchState) updates.ticket_state_id = parseInt(batchState);
|
||||||
if (batchQueue) updates.queue_id = parseInt(batchQueue);
|
if (batchQueue) updates.queue_id = parseInt(batchQueue);
|
||||||
|
if (batchType) updates.type_id = parseInt(batchType);
|
||||||
if (batchOwner) updates.user_id = parseInt(batchOwner);
|
if (batchOwner) updates.user_id = parseInt(batchOwner);
|
||||||
if (batchResponsible) {
|
if (batchResponsible) {
|
||||||
updates.responsible_user_id = parseInt(batchResponsible);
|
updates.responsible_user_id = parseInt(batchResponsible);
|
||||||
|
|||||||
+2
-1
@@ -1417,6 +1417,7 @@ router.patch('/batch/update', async (req, res) => {
|
|||||||
if (updates.ticket_state_id !== undefined) ticketFields.StateID = updates.ticket_state_id;
|
if (updates.ticket_state_id !== undefined) ticketFields.StateID = updates.ticket_state_id;
|
||||||
if (updates.ticket_priority_id !== undefined) ticketFields.PriorityID = updates.ticket_priority_id;
|
if (updates.ticket_priority_id !== undefined) ticketFields.PriorityID = updates.ticket_priority_id;
|
||||||
if (updates.queue_id !== undefined) ticketFields.QueueID = updates.queue_id;
|
if (updates.queue_id !== undefined) ticketFields.QueueID = updates.queue_id;
|
||||||
|
if (updates.type_id !== undefined) ticketFields.TypeID = updates.type_id;
|
||||||
if (updates.user_id !== undefined) ticketFields.OwnerID = updates.user_id;
|
if (updates.user_id !== undefined) ticketFields.OwnerID = updates.user_id;
|
||||||
if (updates.responsible_user_id !== undefined) ticketFields.ResponsibleID = updates.responsible_user_id;
|
if (updates.responsible_user_id !== undefined) ticketFields.ResponsibleID = updates.responsible_user_id;
|
||||||
if (updates.customer_id !== undefined) ticketFields.CustomerID = updates.customer_id;
|
if (updates.customer_id !== undefined) ticketFields.CustomerID = updates.customer_id;
|
||||||
@@ -1471,7 +1472,7 @@ router.patch('/batch/update', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
await client.query('BEGIN');
|
await client.query('BEGIN');
|
||||||
|
|
||||||
const allowedFields = ['ticket_state_id', 'ticket_priority_id', 'queue_id', 'user_id', 'responsible_user_id', 'customer_id', 'customer_user_id'];
|
const allowedFields = ['ticket_state_id', 'ticket_priority_id', 'queue_id', 'type_id', 'user_id', 'responsible_user_id', 'customer_id', 'customer_user_id'];
|
||||||
const setClauses = [];
|
const setClauses = [];
|
||||||
const setParams = [];
|
const setParams = [];
|
||||||
let pIdx = 1;
|
let pIdx = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user