261 lines
11 KiB
PHP
261 lines
11 KiB
PHP
@extends('layouts.app-universal-v2')
|
|
|
|
@section('title', 'Gestione Archivi di Sistema')
|
|
|
|
@section('content')
|
|
<div class="container-fluid">
|
|
<!-- Header Archivi Sistema -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h1 class="h3 mb-0"><i class="fas fa-database text-primary me-2"></i>Gestione Archivi di Sistema</h1>
|
|
<p class="text-muted mb-0">Gestione e sincronizzazione archivi di sistema per NetGesCon</p>
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#importModal">
|
|
<i class="fas fa-upload me-2"></i>Importa ZIP
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistiche Generali -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-body text-center">
|
|
<div class="display-6 text-primary mb-2">
|
|
<i class="fas fa-city"></i>
|
|
</div>
|
|
<h5 class="card-title">{{ number_format($stats['comuni_count']) }}</h5>
|
|
<p class="card-text text-muted">Comuni Italiani</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-body text-center">
|
|
<div class="display-6 text-success mb-2">
|
|
<i class="fas fa-clock"></i>
|
|
</div>
|
|
<h5 class="card-title">
|
|
@if($stats['last_import'])
|
|
{{ \Carbon\Carbon::parse($stats['last_import'])->format('d/m/Y') }}
|
|
@else
|
|
Mai
|
|
@endif
|
|
</h5>
|
|
<p class="card-text text-muted">Ultimo Import</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-body text-center">
|
|
<div class="display-6 text-warning mb-2">
|
|
<i class="fas fa-hdd"></i>
|
|
</div>
|
|
<h5 class="card-title">{{ $stats['storage_size'] }}</h5>
|
|
<p class="card-text text-muted">Spazio Utilizzato</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-body text-center">
|
|
<div class="display-6 text-info mb-2">
|
|
<i class="fas fa-archive"></i>
|
|
</div>
|
|
<h5 class="card-title">{{ count($stats['available_archives']) }}</h5>
|
|
<p class="card-text text-muted">Archivi Disponibili</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Lista Archivi Disponibili -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-list me-2"></i>Archivi di Sistema
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
@foreach($stats['available_archives'] as $key => $archive)
|
|
<div class="col-md-4 mb-3">
|
|
<div class="card h-100">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-start mb-3">
|
|
<h6 class="card-title">{{ $archive['nome'] }}</h6>
|
|
@if($archive['ultima_sincronizzazione'])
|
|
<span class="badge bg-success">Sincronizzato</span>
|
|
@else
|
|
<span class="badge bg-warning">Non sincronizzato</span>
|
|
@endif
|
|
</div>
|
|
<p class="card-text text-muted">{{ $archive['descrizione'] }}</p>
|
|
|
|
@if($archive['ultima_sincronizzazione'])
|
|
<small class="text-muted">
|
|
Ultimo aggiornamento: {{ \Carbon\Carbon::parse($archive['ultima_sincronizzazione'])->format('d/m/Y H:i') }}
|
|
</small>
|
|
@endif
|
|
</div>
|
|
<div class="card-footer bg-transparent">
|
|
<div class="btn-group w-100" role="group">
|
|
@if($key === 'comuni_italiani')
|
|
<a href="{{ route('superadmin.archivi.comuni') }}" class="btn btn-outline-primary btn-sm">
|
|
<i class="fas fa-eye me-1"></i>Visualizza
|
|
</a>
|
|
@endif
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="importArchive('{{ $key }}')">
|
|
<i class="fas fa-sync me-1"></i>Importa
|
|
</button>
|
|
@if($key === 'comuni_italiani')
|
|
<button class="btn btn-outline-info btn-sm" onclick="sincronizzaIstat()">
|
|
<i class="fas fa-cloud-download-alt me-1"></i>ISTAT
|
|
</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Import ZIP -->
|
|
<div class="modal fade" id="importModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-upload me-2"></i>Importa Archivio ZIP</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="importForm" enctype="multipart/form-data">
|
|
@csrf
|
|
<div class="mb-3">
|
|
<label for="tipo_archivio" class="form-label">Tipo Archivio</label>
|
|
<select class="form-select" id="tipo_archivio" name="tipo_archivio" required>
|
|
<option value="">Seleziona tipo archivio...</option>
|
|
<option value="comuni_italiani">Comuni Italiani</option>
|
|
<option value="province">Province</option>
|
|
<option value="regioni">Regioni</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="zip_file" class="form-label">File ZIP</label>
|
|
<input type="file" class="form-control" id="zip_file" name="zip_file" accept=".zip" required>
|
|
<div class="form-text">
|
|
Carica un file ZIP contenente i dati JSON dell'archivio. Dimensione massima: 50MB.
|
|
</div>
|
|
</div>
|
|
<div class="progress d-none" id="uploadProgress">
|
|
<div class="progress-bar" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
|
|
<button type="button" class="btn btn-primary" onclick="submitImport()">
|
|
<i class="fas fa-upload me-2"></i>Importa
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@endsection
|
|
|
|
@push('scripts')
|
|
<script>
|
|
function importArchive(tipo) {
|
|
document.getElementById('tipo_archivio').value = tipo;
|
|
new bootstrap.Modal(document.getElementById('importModal')).show();
|
|
}
|
|
|
|
function submitImport() {
|
|
const form = document.getElementById('importForm');
|
|
const formData = new FormData(form);
|
|
const progress = document.getElementById('uploadProgress');
|
|
const progressBar = progress.querySelector('.progress-bar');
|
|
|
|
// Mostra progress bar
|
|
progress.classList.remove('d-none');
|
|
|
|
fetch('{{ route("superadmin.archivi.import") }}', {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: {
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
progress.classList.add('d-none');
|
|
|
|
if (data.success) {
|
|
showAlert('success', data.message);
|
|
location.reload(); // Ricarica per aggiornare le statistiche
|
|
} else {
|
|
showAlert('danger', data.message);
|
|
}
|
|
|
|
bootstrap.Modal.getInstance(document.getElementById('importModal')).hide();
|
|
})
|
|
.catch(error => {
|
|
progress.classList.add('d-none');
|
|
showAlert('danger', 'Errore durante l\'importazione: ' + error.message);
|
|
bootstrap.Modal.getInstance(document.getElementById('importModal')).hide();
|
|
});
|
|
}
|
|
|
|
function sincronizzaIstat() {
|
|
if (confirm('Avviare la sincronizzazione automatica con ISTAT?')) {
|
|
fetch('{{ route("superadmin.archivi.sincronizza-istat") }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
|
|
'Content-Type': 'application/json'
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
showAlert('success', data.message);
|
|
location.reload();
|
|
} else {
|
|
showAlert('info', data.message);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
showAlert('danger', 'Errore durante la sincronizzazione: ' + error.message);
|
|
});
|
|
}
|
|
}
|
|
|
|
function showAlert(type, message) {
|
|
const alertHtml = `
|
|
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'danger' ? 'exclamation-circle' : 'info-circle'} me-2"></i>
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
`;
|
|
|
|
const container = document.querySelector('.container-fluid');
|
|
container.insertAdjacentHTML('afterbegin', alertHtml);
|
|
}
|
|
</script>
|
|
@endpush
|