first commit

This commit is contained in:
2026-01-18 12:23:37 +01:00
commit ae792f4996
124 changed files with 19497 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Nuovo Articolo') }}
</h2>
<a href="{{ route('admin.articoli.index') }}" class="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
&larr; Torna alla lista
</a>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-4xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<form method="POST" action="{{ route('admin.articoli.store') }}">
@csrf
<!-- Sezione Ubicazione -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Ubicazione</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="codice_articolo" class="block text-sm font-medium text-gray-700">Codice Articolo *</label>
<input type="text" name="codice_articolo" id="codice_articolo" value="{{ old('codice_articolo') }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
@error('codice_articolo')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<div>
<label for="ciclo" class="block text-sm font-medium text-gray-700">Ciclo</label>
<input type="text" name="ciclo" id="ciclo" value="{{ old('ciclo') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="diametro" class="block text-sm font-medium text-gray-700">Diametro</label>
<input type="text" name="diametro" id="diametro" value="{{ old('diametro') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="posizione" class="block text-sm font-medium text-gray-700">Posizione</label>
<input type="text" name="posizione" id="posizione" value="{{ old('posizione') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="quantita" class="block text-sm font-medium text-gray-700">Quantita</label>
<input type="number" name="quantita" id="quantita" value="{{ old('quantita', 0) }}" min="0"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div class="md:col-span-2">
<label for="descrizione" class="block text-sm font-medium text-gray-700">Descrizione</label>
<textarea name="descrizione" id="descrizione" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">{{ old('descrizione') }}</textarea>
</div>
</div>
</div>
<!-- Sezione Parametri Tecnologici -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Parametri Tecnologici</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="tipo_lavorazione" class="block text-sm font-medium text-gray-700">Tipo di Lavorazione</label>
<input type="text" name="tipo_lavorazione" id="tipo_lavorazione" value="{{ old('tipo_lavorazione') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="materiale_lavorare" class="block text-sm font-medium text-gray-700">Materiale da Lavorare</label>
<input type="text" name="materiale_lavorare" id="materiale_lavorare" value="{{ old('materiale_lavorare') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="maximum_thickness" class="block text-sm font-medium text-gray-700">Maximum Thickness</label>
<input type="text" name="maximum_thickness" id="maximum_thickness" value="{{ old('maximum_thickness') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="speed_rpm" class="block text-sm font-medium text-gray-700">Speed (RPM)</label>
<input type="number" name="speed_rpm" id="speed_rpm" value="{{ old('speed_rpm') }}" min="0"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="feed" class="block text-sm font-medium text-gray-700">Feed</label>
<input type="number" name="feed" id="feed" value="{{ old('feed') }}" min="0" step="0.01"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="max_thrust_a" class="block text-sm font-medium text-gray-700">Max Thrust (A)</label>
<input type="text" name="max_thrust_a" id="max_thrust_a" value="{{ old('max_thrust_a') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="min_torque_a" class="block text-sm font-medium text-gray-700">Min Torque (A)</label>
<input type="text" name="min_torque_a" id="min_torque_a" value="{{ old('min_torque_a') }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="quantita_fori" class="block text-sm font-medium text-gray-700">Quantita Fori</label>
<input type="number" name="quantita_fori" id="quantita_fori" value="{{ old('quantita_fori') }}" min="0"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
</div>
</div>
<div class="flex justify-between">
<a href="{{ route('admin.articoli.index') }}" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded">
&larr; Torna alla lista
</a>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Salva Articolo
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -0,0 +1,138 @@
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Modifica Articolo') }}: {{ $articolo->codice_articolo }}
</h2>
<div class="flex items-center space-x-4">
<a href="{{ route('admin.articoli.create') }}" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
+ Nuovo Articolo
</a>
<a href="{{ route('admin.articoli.index') }}" class="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
&larr; Torna alla lista
</a>
</div>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-4xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<form method="POST" action="{{ route('admin.articoli.update', $articolo) }}">
@csrf
@method('PUT')
<!-- Sezione Ubicazione -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Ubicazione</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="codice_articolo" class="block text-sm font-medium text-gray-700">Codice Articolo *</label>
<input type="text" name="codice_articolo" id="codice_articolo" value="{{ old('codice_articolo', $articolo->codice_articolo) }}" required
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
@error('codice_articolo')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<div>
<label for="ciclo" class="block text-sm font-medium text-gray-700">Ciclo</label>
<input type="text" name="ciclo" id="ciclo" value="{{ old('ciclo', $articolo->ciclo) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="diametro" class="block text-sm font-medium text-gray-700">Diametro</label>
<input type="text" name="diametro" id="diametro" value="{{ old('diametro', $articolo->diametro) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="posizione" class="block text-sm font-medium text-gray-700">Posizione</label>
<input type="text" name="posizione" id="posizione" value="{{ old('posizione', $articolo->posizione) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="quantita" class="block text-sm font-medium text-gray-700">Quantita</label>
<input type="number" name="quantita" id="quantita" value="{{ old('quantita', $articolo->quantita) }}" min="0"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div class="md:col-span-2">
<label for="descrizione" class="block text-sm font-medium text-gray-700">Descrizione</label>
<textarea name="descrizione" id="descrizione" rows="3"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">{{ old('descrizione', $articolo->descrizione) }}</textarea>
</div>
</div>
</div>
<!-- Sezione Parametri Tecnologici -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Parametri Tecnologici</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="tipo_lavorazione" class="block text-sm font-medium text-gray-700">Tipo di Lavorazione</label>
<input type="text" name="tipo_lavorazione" id="tipo_lavorazione" value="{{ old('tipo_lavorazione', $articolo->tipo_lavorazione) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="materiale_lavorare" class="block text-sm font-medium text-gray-700">Materiale da Lavorare</label>
<input type="text" name="materiale_lavorare" id="materiale_lavorare" value="{{ old('materiale_lavorare', $articolo->materiale_lavorare) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="maximum_thickness" class="block text-sm font-medium text-gray-700">Maximum Thickness</label>
<input type="text" name="maximum_thickness" id="maximum_thickness" value="{{ old('maximum_thickness', $articolo->maximum_thickness) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="speed_rpm" class="block text-sm font-medium text-gray-700">Speed (RPM)</label>
<input type="number" name="speed_rpm" id="speed_rpm" value="{{ old('speed_rpm', $articolo->speed_rpm) }}" min="0"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="feed" class="block text-sm font-medium text-gray-700">Feed</label>
<input type="number" name="feed" id="feed" value="{{ old('feed', $articolo->feed) }}" min="0" step="0.01"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="max_thrust_a" class="block text-sm font-medium text-gray-700">Max Thrust (A)</label>
<input type="text" name="max_thrust_a" id="max_thrust_a" value="{{ old('max_thrust_a', $articolo->max_thrust_a) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="min_torque_a" class="block text-sm font-medium text-gray-700">Min Torque (A)</label>
<input type="text" name="min_torque_a" id="min_torque_a" value="{{ old('min_torque_a', $articolo->min_torque_a) }}"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div>
<label for="quantita_fori" class="block text-sm font-medium text-gray-700">Quantita Fori</label>
<input type="number" name="quantita_fori" id="quantita_fori" value="{{ old('quantita_fori', $articolo->quantita_fori) }}" min="0"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
</div>
</div>
<div class="flex justify-between">
<a href="{{ route('admin.articoli.index') }}" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded">
&larr; Torna alla lista
</a>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Salva Articolo
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@@ -0,0 +1,407 @@
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Gestione Articoli') }}
</h2>
<div class="flex items-center space-x-4">
<button type="button" id="btn-stampa-qr" onclick="stampaQrSelezionati()"
class="bg-purple-500 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded hidden">
Stampa QR CODE (<span id="count-selezionati">0</span>)
</button>
<button type="button" onclick="openImportModal()"
class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
Importa Excel
</button>
<a href="{{ route('admin.articoli.create') }}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
+ Nuovo Articolo
</a>
</div>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
@if (session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
{{ session('success') }}
</div>
@endif
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<!-- Search Form -->
<form method="GET" action="{{ route('admin.articoli.index') }}" class="mb-6">
<div class="flex gap-4">
<input type="text" name="search" value="{{ request('search') }}"
placeholder="Cerca per codice, descrizione o ciclo..."
class="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
<button type="submit" class="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
Cerca
</button>
@if(request('search'))
<a href="{{ route('admin.articoli.index') }}" class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded">
Reset
</a>
@endif
</div>
</form>
<!-- Table -->
<table class="w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-10">
<input type="checkbox" id="select-all" onclick="toggleSelectAll()"
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
</th>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Codice</th>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ciclo</th>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Descrizione</th>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Posizione</th>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Quantita</th>
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Azioni</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
@forelse ($articoli as $articolo)
<tr class="{{ $loop->even ? 'bg-gray-100' : 'bg-white' }} hover:bg-blue-50 cursor-pointer" onclick="goToDetail(event, '{{ route('admin.articoli.show', $articolo) }}')">
<td class="px-3 py-2 whitespace-nowrap" onclick="event.stopPropagation()">
<input type="checkbox" class="articolo-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500"
value="{{ $articolo->id }}" onchange="updateSelection()">
</td>
<td class="px-3 py-2 whitespace-nowrap text-sm font-medium text-gray-900">
{{ $articolo->codice_articolo }}
</td>
<td class="px-3 py-2 whitespace-nowrap text-sm text-gray-500">
{{ $articolo->ciclo }}
</td>
<td class="px-3 py-2 text-sm text-gray-500 truncate max-w-xs">
{{ $articolo->descrizione }}
</td>
<td class="px-3 py-2 whitespace-nowrap text-sm text-gray-500">
{{ $articolo->posizione }}
</td>
<td class="px-3 py-2 whitespace-nowrap text-sm text-gray-500">
{{ $articolo->quantita }}
</td>
<td class="px-3 py-2 whitespace-nowrap text-sm font-medium space-x-2" onclick="event.stopPropagation()">
<a href="{{ route('admin.articoli.show', $articolo) }}" class="text-blue-600 hover:text-blue-900">Dettagli</a>
<a href="{{ route('admin.articoli.edit', $articolo) }}" class="text-indigo-600 hover:text-indigo-900">Modifica</a>
<form action="{{ route('admin.articoli.destroy', $articolo) }}" method="POST" class="inline" onsubmit="return confirm('Sei sicuro di voler eliminare questo articolo?');">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-900">Elimina</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-3 py-4 text-center text-gray-500">
Nessun articolo trovato.
</td>
</tr>
@endforelse
</tbody>
</table>
<!-- Pagination -->
<div class="mt-4">
{{ $articoli->withQueryString()->links() }}
</div>
</div>
</div>
</div>
</div>
<!-- Import Modal Overlay -->
<div id="import-modal" class="fixed inset-0 z-50" style="display: none;">
<!-- Backdrop -->
<div class="fixed inset-0" style="background-color: rgba(0, 0, 0, 0.5);" onclick="closeImportModal()"></div>
<!-- Modal Content -->
<div class="fixed inset-0 flex items-center justify-center p-4">
<div class="relative bg-white rounded-lg shadow-xl w-half max-w-md p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Importa Articoli da Excel</h3>
<button onclick="closeImportModal()" class="text-gray-400 hover:text-gray-600">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<form id="import-form" enctype="multipart/form-data">
@csrf
<!-- Drop Zone -->
<div id="drop-zone" class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center cursor-pointer hover:border-blue-500 transition-colors">
<svg style="width: 48px; height: 48px;" class="mx-auto text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
</svg>
<p class="mt-2 text-sm text-gray-600">
<span class="font-semibold text-blue-600">Clicca per selezionare</span> o trascina un file Excel
</p>
<p class="mt-1 text-xs text-gray-500">Solo file .xlsx o .xls</p>
<input type="file" id="file-input" name="file" accept=".xlsx,.xls" class="hidden">
</div>
<!-- Selected File -->
<div id="selected-file" class="hidden mt-4 p-3 bg-gray-50 rounded-lg flex items-center justify-between">
<div class="flex items-center">
<svg class="w-8 h-8 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
<span id="file-name" class="ml-2 text-sm text-gray-700"></span>
</div>
<button type="button" onclick="clearFile()" class="text-red-500 hover:text-red-700">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Clean Import Checkbox -->
<div class="mt-4">
<label class="flex items-center">
<input type="checkbox" id="clean-import" name="clean_import" value="1"
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
<span class="ml-2 text-sm text-gray-700">Importazione pulita</span>
</label>
<p class="mt-1 ml-6 text-xs text-gray-500">
Cancella tutti gli articoli esistenti prima dell'importazione
</p>
</div>
<!-- Progress Bar -->
<div id="progress-container" class="hidden mt-4">
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div id="progress-bar" class="bg-blue-600 h-2.5 rounded-full transition-all duration-300" style="width: 0%"></div>
</div>
<p id="progress-text" class="text-sm text-gray-600 mt-2 text-center">Caricamento in corso...</p>
</div>
<!-- Result Message -->
<div id="result-message" class="hidden mt-4 p-3 rounded-lg"></div>
<!-- Buttons -->
<div class="mt-6 flex justify-end space-x-4">
<button type="button" onclick="closeImportModal()"
style="padding: 8px 16px; background-color: #d1d5db; color: #374151; border-radius: 6px; border: none; cursor: pointer;">
Annulla
</button>
<button type="submit" id="import-btn"
style="padding: 8px 16px; background-color: #9ca3af; color: white; border-radius: 6px; border: none; cursor: not-allowed;">
Importa
</button>
</div>
</form>
</div>
</div>
</div>
<script>
function goToDetail(event, url) {
window.location.href = url;
}
function toggleSelectAll() {
const selectAll = document.getElementById('select-all');
const checkboxes = document.querySelectorAll('.articolo-checkbox');
checkboxes.forEach(cb => cb.checked = selectAll.checked);
updateSelection();
}
function updateSelection() {
const checkboxes = document.querySelectorAll('.articolo-checkbox:checked');
const count = checkboxes.length;
const btn = document.getElementById('btn-stampa-qr');
const countSpan = document.getElementById('count-selezionati');
countSpan.textContent = count;
if (count > 0) {
btn.classList.remove('hidden');
} else {
btn.classList.add('hidden');
}
// Update select-all checkbox state
const allCheckboxes = document.querySelectorAll('.articolo-checkbox');
const selectAll = document.getElementById('select-all');
selectAll.checked = allCheckboxes.length > 0 && count === allCheckboxes.length;
selectAll.indeterminate = count > 0 && count < allCheckboxes.length;
}
function stampaQrSelezionati() {
const checkboxes = document.querySelectorAll('.articolo-checkbox:checked');
const ids = Array.from(checkboxes).map(cb => cb.value);
if (ids.length === 0) {
alert('Seleziona almeno un articolo');
return;
}
// Open PDF in new window
const url = '{{ route('admin.articoli.print-qrcodes') }}?ids=' + ids.join(',');
window.open(url, '_blank');
}
// Import Modal Functions
const dropZone = document.getElementById('drop-zone');
const fileInput = document.getElementById('file-input');
const importForm = document.getElementById('import-form');
const importBtn = document.getElementById('import-btn');
const selectedFile = document.getElementById('selected-file');
const fileName = document.getElementById('file-name');
const progressContainer = document.getElementById('progress-container');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
const resultMessage = document.getElementById('result-message');
function openImportModal() {
document.getElementById('import-modal').style.display = 'flex';
resetImportForm();
}
function closeImportModal() {
document.getElementById('import-modal').style.display = 'none';
resetImportForm();
}
function resetImportForm() {
importForm.reset();
fileInput.value = '';
selectedFile.classList.add('hidden');
dropZone.classList.remove('hidden');
progressContainer.classList.add('hidden');
resultMessage.classList.add('hidden');
importBtn.disabled = true;
progressBar.style.width = '0%';
}
function clearFile() {
fileInput.value = '';
selectedFile.classList.add('hidden');
dropZone.classList.remove('hidden');
importBtn.disabled = true;
importBtn.style.backgroundColor = '#9ca3af';
importBtn.style.cursor = 'not-allowed';
}
function handleFileSelect(file) {
if (file && (file.name.endsWith('.xlsx') || file.name.endsWith('.xls'))) {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
fileName.textContent = file.name;
selectedFile.classList.remove('hidden');
dropZone.classList.add('hidden');
importBtn.disabled = false;
importBtn.style.backgroundColor = '#2563eb';
importBtn.style.cursor = 'pointer';
resultMessage.classList.add('hidden');
} else {
alert('Per favore seleziona un file Excel (.xlsx o .xls)');
}
}
// Click to upload
dropZone.addEventListener('click', () => fileInput.click());
// File input change
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
handleFileSelect(e.target.files[0]);
}
});
// Drag and drop
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('border-blue-500', 'bg-blue-50');
});
dropZone.addEventListener('dragleave', (e) => {
e.preventDefault();
dropZone.classList.remove('border-blue-500', 'bg-blue-50');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('border-blue-500', 'bg-blue-50');
if (e.dataTransfer.files.length > 0) {
handleFileSelect(e.dataTransfer.files[0]);
}
});
// Form submit
importForm.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(importForm);
formData.append('clean_import', document.getElementById('clean-import').checked ? '1' : '0');
// Show progress
progressContainer.classList.remove('hidden');
importBtn.disabled = true;
progressBar.style.width = '30%';
progressText.textContent = 'Caricamento file...';
try {
const response = await fetch('{{ route('admin.articoli.import') }}', {
method: 'POST',
body: formData,
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
});
progressBar.style.width = '70%';
progressText.textContent = 'Elaborazione in corso...';
const data = await response.json();
progressBar.style.width = '100%';
if (data.success) {
resultMessage.className = 'mt-4 p-3 rounded-lg bg-green-100 text-green-700';
resultMessage.textContent = data.message;
progressText.textContent = 'Completato!';
// Reload page after 2 seconds
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
resultMessage.className = 'mt-4 p-3 rounded-lg bg-red-100 text-red-700';
resultMessage.textContent = data.message;
progressContainer.classList.add('hidden');
importBtn.disabled = false;
}
resultMessage.classList.remove('hidden');
} catch (error) {
progressContainer.classList.add('hidden');
resultMessage.className = 'mt-4 p-3 rounded-lg bg-red-100 text-red-700';
resultMessage.textContent = 'Errore durante l\'importazione: ' + error.message;
resultMessage.classList.remove('hidden');
importBtn.disabled = false;
}
});
// Close modal on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeImportModal();
}
});
// Close modal on outside click
document.getElementById('import-modal').addEventListener('click', (e) => {
if (e.target === document.getElementById('import-modal')) {
closeImportModal();
}
});
</script>
</x-app-layout>

View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QR Codes Articoli</title>
<style>
@page {
margin: 10mm;
}
body {
font-family: Arial, sans-serif;
font-size: 6pt;
margin: 0;
padding: 0;
}
.qr-container {
display: inline-block;
width: 15mm;
text-align: center;
margin: 2mm;
vertical-align: top;
page-break-inside: avoid;
}
.qr-code {
width: 10mm;
height: 10mm;
}
.qr-label {
font-size: 5pt;
margin-top: 1mm;
word-break: break-all;
line-height: 1.2;
max-width: 15mm;
overflow: hidden;
}
</style>
</head>
<body>
@foreach($articoliWithQr as $item)
<div class="qr-container">
<img src="data:image/png;base64,{{ $item['qr_base64'] }}" class="qr-code" alt="QR Code">
<div class="qr-label">{{ $item['articolo']->codice_articolo }}</div>
</div>
@endforeach
</body>
</html>

View File

@@ -0,0 +1,150 @@
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Dettaglio Articolo') }}: {{ $articolo->codice_articolo }}
</h2>
<div class="space-x-2">
<a href="{{ route('admin.articoli.edit', $articolo) }}" class="bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-2 px-4 rounded">
Modifica
</a>
<a href="{{ route('admin.articoli.index') }}" class="text-gray-600 hover:text-gray-900">
&larr; Torna alla lista
</a>
</div>
</div>
</x-slot>
<div class="py-12">
<div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
@if (session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
{{ session('success') }}
</div>
@endif
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Dettagli Articolo -->
<div class="lg:col-span-2 space-y-6">
<!-- Sezione Ubicazione -->
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Ubicazione</h3>
<dl class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<dt class="text-sm font-medium text-gray-500">Codice Articolo</dt>
<dd class="mt-1 text-sm text-gray-900 font-semibold">{{ $articolo->codice_articolo }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Ciclo</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->ciclo ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Diametro</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->diametro ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Posizione</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->posizione ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Quantita</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->quantita }}</dd>
</div>
<div class="md:col-span-2">
<dt class="text-sm font-medium text-gray-500">Descrizione</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->descrizione ?? '-' }}</dd>
</div>
</dl>
</div>
</div>
<!-- Sezione Parametri Tecnologici -->
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Parametri Tecnologici</h3>
<dl class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<dt class="text-sm font-medium text-gray-500">Tipo di Lavorazione</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->tipo_lavorazione ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Materiale da Lavorare</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->materiale_lavorare ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Maximum Thickness</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->maximum_thickness ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Speed (RPM)</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->speed_rpm ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Feed</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->feed ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Max Thrust (A)</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->max_thrust_a ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Min Torque (A)</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->min_torque_a ?? '-' }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Quantita Fori</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->quantita_fori ?? '-' }}</dd>
</div>
</dl>
</div>
</div>
</div>
<!-- Sezione QR Code -->
<div class="lg:col-span-1">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">QR Code</h3>
<div class="flex flex-col items-center">
<div class="bg-white p-4 border rounded-lg mb-4">
<img src="{{ route('admin.articoli.qrcode', $articolo) }}" alt="QR Code" class="w-48 h-48">
</div>
<p class="text-xs text-gray-500 mb-4 text-center break-all">
{{ $articolo->qr_url }}
</p>
<div class="space-y-2 w-full">
<a href="{{ route('admin.articoli.qrcode.download', $articolo) }}"
class="block w-full text-center bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
Scarica QR Code
</a>
<button onclick="window.print()"
class="block w-full text-center bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
Stampa
</button>
</div>
</div>
</div>
</div>
<!-- Info -->
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg mt-6">
<div class="p-6">
<h3 class="text-lg font-medium text-gray-900 mb-4 pb-2 border-b">Informazioni</h3>
<dl class="space-y-2">
<div>
<dt class="text-sm font-medium text-gray-500">Creato il</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->created_at->format('d/m/Y H:i') }}</dd>
</div>
<div>
<dt class="text-sm font-medium text-gray-500">Ultima modifica</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $articolo->updated_at->format('d/m/Y H:i') }}</dd>
</div>
</dl>
</div>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>