setup viste
This commit is contained in:
@@ -15,105 +15,159 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="filters-tab" data-toggle="tab" href="#filters-panel" role="tab">
|
||||
<i class="fas fa-filter mr-1"></i> Filtri
|
||||
<a class="nav-link" id="vistas-tab" data-toggle="tab" href="#vistas-panel" role="tab">
|
||||
<i class="fas fa-save mr-1"></i> Viste
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="search-tab" data-toggle="tab" href="#search-panel" role="tab">
|
||||
<i class="fas fa-search mr-1"></i> Ricerca
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="export-tab" data-toggle="tab" href="#export-panel" role="tab">
|
||||
<i class="fas fa-download mr-1"></i> Esporta
|
||||
<a class="nav-link" id="print-tab" data-toggle="tab" href="#print-panel" role="tab">
|
||||
<i class="fas fa-print mr-1"></i> Stampa
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="tab-content p-3">
|
||||
<div class="tab-pane fade show active" id="columns-panel" role="tabpanel">
|
||||
<h6>Seleziona le colonne da visualizzare:</h6>
|
||||
<div class="row">
|
||||
<h6 class="mb-3">Seleziona colonne, regola larghezza e riordina:</h6>
|
||||
<p class="small text-muted mb-3">
|
||||
<i class="fas fa-arrows-alt mr-1"></i> Trascina le intestazioni per riordinare ·
|
||||
<i class="fas fa-arrows-alt-h mr-1"></i> Trascina il bordo destro di una cella per ridimensionare
|
||||
</p>
|
||||
<div id="column-list" class="mb-3">
|
||||
@foreach($tableColumns as $col)
|
||||
<div class="col-md-4">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input column-toggle"
|
||||
id="col-{{ $col['key'] }}" data-column="{{ $col['key'] }}"
|
||||
{{ ($col['visible'] ?? true) ? 'checked' : '' }}>
|
||||
<label class="custom-control-label" for="col-{{ $col['key'] }}">
|
||||
{{ $col['label'] }}
|
||||
</label>
|
||||
<div class="form-row align-items-center mb-2 column-config-item" data-column="{{ $col['key'] }}">
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-grip-vertical text-muted" style="cursor:grab;"></i>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input column-toggle"
|
||||
id="col-{{ $col['key'] }}" data-column="{{ $col['key'] }}"
|
||||
{{ ($col['visible'] ?? true) ? 'checked' : '' }}>
|
||||
<label class="custom-control-label" for="col-{{ $col['key'] }}">
|
||||
{{ $col['label'] }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="number" class="form-control form-control-sm column-width-input"
|
||||
data-column="{{ $col['key'] }}"
|
||||
value="{{ isset($columnWidths[$col['key']]) ? intval(str_replace('px', '', $columnWidths[$col['key']])) : '' }}"
|
||||
placeholder="auto" min="30" style="max-width:80px;">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">px</span>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ml-1 reset-col-width" data-column="{{ $col['key'] }}"
|
||||
title="Reset larghezza">
|
||||
<i class="fas fa-undo-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-secondary" onclick="resetAllColumnWidths()">
|
||||
<i class="fas fa-undo-alt mr-1"></i> Reset tutte larghezze
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="filters-panel" role="tabpanel">
|
||||
<h6>Aggiungi filtri:</h6>
|
||||
<div id="filters-container">
|
||||
<div class="filter-row mb-2">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<select class="form-control form-control-sm filter-column">
|
||||
<option value="">Seleziona colonna...</option>
|
||||
@foreach($tableColumns as $col)
|
||||
<option value="{{ $col['key'] }}">{{ $col['label'] }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
<div class="tab-pane fade" id="vistas-panel" role="tabpanel">
|
||||
<h6 class="mb-2">Viste salvate</h6>
|
||||
<div id="vistas-list" class="mb-3">
|
||||
@php
|
||||
$entityType = $entityType ?? 'individui';
|
||||
$userVistas = $userVistas ?? collect();
|
||||
@endphp
|
||||
@if($userVistas->count() > 0)
|
||||
<div class="list-group mb-3" id="vistas-list-group">
|
||||
@foreach($userVistas as $v)
|
||||
<div class="list-group-item list-group-item-action d-flex align-items-center py-2 {{ $vista && $vista->id === $v->id ? 'active' : '' }}">
|
||||
<div class="mr-auto">
|
||||
@if($v->is_default)
|
||||
<i class="fas fa-star text-warning mr-1" title="Predefinita"></i>
|
||||
@else
|
||||
<i class="fas fa-file-alt text-muted mr-1"></i>
|
||||
@endif
|
||||
<span>{{ $v->nome }}</span>
|
||||
@if($v->colonne_visibili)
|
||||
<span class="badge badge-light ml-1">{{ count($v->colonne_visibili) }} col.</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-control form-control-sm filter-operator">
|
||||
<option value="contains">Contiene</option>
|
||||
<option value="equals">Uguale a</option>
|
||||
<option value="starts">Inizia con</option>
|
||||
<option value="ends">Finisce con</option>
|
||||
<option value="gt">Maggiore di</option>
|
||||
<option value="lt">Minore di</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control form-control-sm filter-value" placeholder="Valore">
|
||||
<div class="ml-2">
|
||||
<a href="?vista_id={{ $v->id }}" class="btn btn-xs btn-primary" title="Applica vista">
|
||||
<i class="fas fa-play"></i>
|
||||
</a>
|
||||
@if(!$v->is_default)
|
||||
<form action="{{ url('/viste/' . $v->id . '/default') }}" method="POST" class="d-inline">
|
||||
@csrf @method('PATCH')
|
||||
<button type="submit" class="btn btn-xs btn-warning" title="Imposta predefinita">
|
||||
<i class="fas fa-star"></i>
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
<button type="button" class="btn btn-xs btn-info edit-vista-btn" title="Modifica vista"
|
||||
data-vista-id="{{ $v->id }}"
|
||||
data-vista-nome="{{ $v->nome }}"
|
||||
data-vista-default="{{ $v->is_default ? 'true' : 'false' }}"
|
||||
data-vista-colonne="{{ json_encode($v->colonne_visibili ?? []) }}">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
<form action="{{ url('/viste/' . $v->id) }}" method="POST" class="d-inline">
|
||||
@csrf @method('DELETE')
|
||||
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Eliminare questa vista?')" title="Elimina">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted text-center py-2">Nessuna vista salvata</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<h6 class="mb-2">Salva vista corrente</h6>
|
||||
<div class="form-row align-items-end">
|
||||
<div class="col">
|
||||
<input type="text" id="vista-nome" class="form-control" placeholder="Nome vista...">
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="vista-default" value="true">
|
||||
<label class="custom-control-label" for="vista-default">Predefinita</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-primary" id="save-vista-btn">
|
||||
<i class="fas fa-save mr-1"></i> Salva
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-xs btn-success mt-2" onclick="addFilterRow()">
|
||||
<i class="fas fa-plus"></i> Aggiungi filtro
|
||||
</button>
|
||||
<button type="button" class="btn btn-xs btn-primary mt-2" id="apply-filters-btn">
|
||||
<i class="fas fa-check"></i> Applica filtri
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="search-panel" role="tabpanel">
|
||||
<div class="form-group">
|
||||
<label>cerca in tutte le colonne:</label>
|
||||
<input type="text" id="table-search" class="form-control" placeholder="Testo da cercare...">
|
||||
|
||||
<div class="tab-pane fade" id="print-panel" role="tabpanel">
|
||||
<h6 class="mb-3">Stampa con impostazioni correnti</h6>
|
||||
<p>La stampa rispetterà le colonne visibili, la larghezza e l'ordine impostati.</p>
|
||||
<button type="button" class="btn btn-primary btn-lg" onclick="window.printWithCurrentSettings ? window.printWithCurrentSettings() : alert('ColumnManager non inizializzato'); return false;">
|
||||
<i class="fas fa-print mr-2"></i> Stampa
|
||||
</button>
|
||||
<hr>
|
||||
<h6 class="mb-2">Opzioni aggiuntive</h6>
|
||||
<div class="custom-control custom-checkbox mb-2">
|
||||
<input type="checkbox" class="custom-control-input" id="print-page-breaks" checked>
|
||||
<label class="custom-control-label" for="print-page-breaks">Interruzione di pagina tra gli elementi</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="export-panel" role="tabpanel">
|
||||
<h6>Esporta i dati visualizzati:</h6>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-success" id="export-csv-btn">
|
||||
<i class="fas fa-file-csv mr-1"></i> Esporta CSV
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" id="export-pdf-btn">
|
||||
<i class="fas fa-file-pdf mr-1"></i> Esporta PDF
|
||||
</button>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="print-background">
|
||||
<label class="custom-control-label" for="print-background">Stampa sfondi e colori</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="mr-auto">
|
||||
<input type="text" id="vista-nome" class="form-control form-control-sm" placeholder="Nome vista..." style="display: inline-block; width: auto;">
|
||||
<button type="button" class="btn btn-primary btn-sm" id="save-vista-btn">
|
||||
<i class="fas fa-save mr-1"></i> Salva Vista
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Chiudi</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,41 +175,160 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function addFilterRow() {
|
||||
const container = document.getElementById('filters-container');
|
||||
const columns = @json($tableColumns);
|
||||
const options = columns.map(c => `<option value="${c.key}">${c.label}</option>`).join('');
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.className = 'filter-row mb-2';
|
||||
div.innerHTML = `
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<select class="form-control form-control-sm filter-column">
|
||||
<option value="">Seleziona colonna...</option>
|
||||
${options}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-control form-control-sm filter-operator">
|
||||
<option value="contains">Contiene</option>
|
||||
<option value="equals">Uguale a</option>
|
||||
<option value="starts">Inizia con</option>
|
||||
<option value="ends">Finisce con</option>
|
||||
<option value="gt">Maggiore di</option>
|
||||
<option value="lt">Minore di</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control form-control-sm filter-value" placeholder="Valore">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="button" class="btn btn-danger btn-sm" onclick="this.closest('.filter-row').remove()">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
function resetAllColumnWidths() {
|
||||
document.querySelectorAll('.column-width-input').forEach(inp => { inp.value = ''; });
|
||||
document.querySelectorAll('.column-config-item').forEach(item => {
|
||||
const th = document.querySelector(`th[data-column="${item.dataset.column}"]`);
|
||||
if (th) th.style.width = '';
|
||||
});
|
||||
if (window.columnManager) {
|
||||
window.columnManager.columnWidths = {};
|
||||
window.columnManager.persistState();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
function syncColumnListToTable() {
|
||||
const items = document.querySelectorAll('#column-list .column-config-item');
|
||||
const keys = Array.from(items).map(i => i.dataset.column);
|
||||
if (window.columnManager && keys.length > 0) {
|
||||
window.columnManager.reorderColumns(keys);
|
||||
}
|
||||
}
|
||||
|
||||
let editingVistaId = null;
|
||||
|
||||
function editVista(id, nome, isDefault, colonneVisibili) {
|
||||
editingVistaId = id;
|
||||
document.getElementById('vista-nome').value = nome;
|
||||
document.getElementById('vista-default').checked = isDefault;
|
||||
document.querySelectorAll('.column-toggle').forEach(cb => {
|
||||
cb.checked = colonneVisibili.includes(cb.dataset.column);
|
||||
if (window.columnManager) window.columnManager.setVisible(cb.dataset.column, cb.checked);
|
||||
});
|
||||
document.getElementById('save-vista-btn').innerHTML = '<i class="fas fa-save mr-1"></i> Aggiorna';
|
||||
document.getElementById('vistas-tab').click();
|
||||
}
|
||||
|
||||
function initTableSettings() {
|
||||
const columnList = document.getElementById('column-list');
|
||||
if (!columnList) return;
|
||||
|
||||
let dragItem = null;
|
||||
|
||||
columnList.querySelectorAll('.column-config-item').forEach(item => {
|
||||
const grip = item.querySelector('.fa-grip-vertical');
|
||||
if (!grip) return;
|
||||
grip.addEventListener('mousedown', function () { item.draggable = true; });
|
||||
item.addEventListener('dragstart', function (e) {
|
||||
dragItem = this; e.dataTransfer.effectAllowed = 'move'; this.classList.add('dragging');
|
||||
});
|
||||
item.addEventListener('dragend', function () {
|
||||
this.classList.remove('dragging'); this.draggable = false; dragItem = null;
|
||||
});
|
||||
item.addEventListener('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
if (!dragItem || dragItem === this) return;
|
||||
const rect = this.getBoundingClientRect();
|
||||
const midY = rect.top + rect.height / 2;
|
||||
if (e.clientY < midY) columnList.insertBefore(dragItem, this);
|
||||
else columnList.insertBefore(dragItem, this.nextSibling);
|
||||
});
|
||||
});
|
||||
|
||||
columnList.addEventListener('drop', function () {
|
||||
const items = Array.from(columnList.querySelectorAll('.column-config-item'));
|
||||
const newOrder = items.map(i => i.dataset.column);
|
||||
if (window.columnManager && newOrder.length > 0) window.columnManager.reorderColumns(newOrder);
|
||||
syncColumnListToTable();
|
||||
});
|
||||
|
||||
columnList.querySelectorAll('.column-toggle').forEach(cb => {
|
||||
cb.addEventListener('change', function () {
|
||||
if (window.columnManager) window.columnManager.setVisible(this.dataset.column, this.checked);
|
||||
});
|
||||
});
|
||||
|
||||
columnList.querySelectorAll('.column-width-input').forEach(inp => {
|
||||
inp.addEventListener('change', function () {
|
||||
const key = this.dataset.column;
|
||||
const val = parseInt(this.value);
|
||||
const th = document.querySelector(`th[data-column="${key}"]`);
|
||||
if (th) {
|
||||
if (val && val >= 30) {
|
||||
th.style.width = val + 'px';
|
||||
if (window.columnManager) {
|
||||
window.columnManager.columnWidths[key] = val + 'px';
|
||||
window.columnManager.persistState();
|
||||
}
|
||||
} else {
|
||||
th.style.width = '';
|
||||
if (window.columnManager) {
|
||||
delete window.columnManager.columnWidths[key];
|
||||
window.columnManager.persistState();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
columnList.querySelectorAll('.reset-col-width').forEach(btn => {
|
||||
btn.addEventListener('click', function () {
|
||||
const key = this.dataset.column;
|
||||
const inp = document.querySelector(`.column-width-input[data-column="${key}"]`);
|
||||
if (inp) inp.value = '';
|
||||
const th = document.querySelector(`th[data-column="${key}"]`);
|
||||
if (th) th.style.width = '';
|
||||
if (window.columnManager) {
|
||||
delete window.columnManager.columnWidths[key];
|
||||
window.columnManager.persistState();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.edit-vista-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function () {
|
||||
editVista(
|
||||
this.dataset.vistaId,
|
||||
this.dataset.vistaNome,
|
||||
this.dataset.vistaDefault === 'true',
|
||||
JSON.parse(this.dataset.vistaColonne)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('save-vista-btn')?.addEventListener('click', function() {
|
||||
const nome = document.getElementById('vista-nome').value.trim();
|
||||
if (!nome) { alert('Inserisci un nome per la vista'); return; }
|
||||
|
||||
const colonneVisibili = Array.from(document.querySelectorAll('.column-toggle:checked')).map(cb => cb.dataset.column);
|
||||
const larghezze = {};
|
||||
document.querySelectorAll('.column-width-input').forEach(inp => {
|
||||
const val = parseInt(inp.value);
|
||||
if (val && val >= 30) larghezze[inp.dataset.column] = val + 'px';
|
||||
});
|
||||
const ordine = Array.from(document.querySelectorAll('#column-list .column-config-item')).map(i => i.dataset.column);
|
||||
const isDefault = document.getElementById('vista-default')?.checked || false;
|
||||
const entityType = '{{ $entityType ?? 'individui' }}';
|
||||
|
||||
const isEditing = editingVistaId !== null;
|
||||
const url = isEditing ? '/viste/' + editingVistaId : '/viste';
|
||||
const method = isEditing ? 'PUT' : 'POST';
|
||||
|
||||
fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content || ''
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nome, tipo: entityType, colonne_visibili: colonneVisibili,
|
||||
colonne_larghezze: larghezze, colonne_ordine: ordine,
|
||||
colonne_ordinamento: [], is_default: isDefault,
|
||||
})
|
||||
})
|
||||
.then(response => response.ok ? (alert(isEditing ? 'Vista aggiornata!' : 'Vista salvata!'), window.location.reload()) : response.text().then(t => { throw new Error(t); }))
|
||||
.catch(err => alert('Errore salvataggio vista: ' + err.message));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user