578 lines
46 KiB
PHP
578 lines
46 KiB
PHP
<x-filament-panels::page>
|
|
@php
|
|
$tabs = [
|
|
'protocollo-comunicazioni' => 'Protocollo comunicazioni',
|
|
'archivio-digitale' => 'Archivio digitale',
|
|
'template-drive' => 'Template Drive',
|
|
'archivio-fisico' => 'Archivio fisico',
|
|
'permessi' => 'Permessi e cartelle',
|
|
];
|
|
$stats = $this->hubStats;
|
|
$protocolloStats = $this->protocolloComunicazioniStats;
|
|
@endphp
|
|
|
|
<div class="space-y-6">
|
|
<div class="rounded-2xl border border-slate-200 bg-gradient-to-r from-amber-50 via-white to-sky-50 p-5">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
|
<div>
|
|
<div class="text-sm font-semibold uppercase tracking-[0.18em] text-slate-500">Hub Documenti</div>
|
|
<h2 class="mt-2 text-2xl font-semibold text-slate-900">Archivio digitale e fisico nello stesso flusso</h2>
|
|
<p class="mt-2 max-w-3xl text-sm text-slate-600">Questa pagina diventa la base unica per PDF, struttura Drive, contenitori fisici e regole di visibilita. Il modello resta coerente con il passaggio consegne dello stabile e con la futura gestione studio.</p>
|
|
</div>
|
|
<div class="rounded-xl border border-white/70 bg-white/80 px-4 py-3 text-right shadow-sm">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Codice mnemonico suggerito</div>
|
|
<div class="mt-1 text-xl font-semibold text-slate-900">{{ $this->mnemonicCodeHint ?? 'STB00000' }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">Formato guida per etichette, QR e archivio fisico.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-5 grid gap-3 md:grid-cols-2 xl:grid-cols-4">
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Documenti</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $stats['documenti'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Archivio PDF censito.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Archiviati</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $stats['archiviati'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Documenti chiusi e consolidati.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">In scadenza</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $stats['in_scadenza'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Finestra dei prossimi 30 giorni.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Template Drive</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $stats['template_drive'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Cartelle base replicabili per stabile.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-2">
|
|
@foreach($tabs as $tabKey => $tabLabel)
|
|
<button
|
|
type="button"
|
|
wire:click="selectHubTab('{{ $tabKey }}')"
|
|
@class([
|
|
'rounded-full px-4 py-2 text-sm font-medium transition',
|
|
'bg-slate-900 text-white shadow-sm' => $this->hubTab === $tabKey,
|
|
'bg-white text-slate-600 ring-1 ring-inset ring-slate-300 hover:bg-slate-50' => $this->hubTab !== $tabKey,
|
|
])
|
|
>
|
|
{{ $tabLabel }}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
|
|
@if($this->hubTab === 'protocollo-comunicazioni')
|
|
<x-filament::section>
|
|
<x-slot name="heading">Protocollo comunicazioni</x-slot>
|
|
<x-slot name="description">Prima tab operativa per l'amministratore: ultimi documenti protocollati, filtri rapidi e vista a box con anteprima PDF o lista compatta.</x-slot>
|
|
|
|
<div class="space-y-4">
|
|
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Protocollo visibile</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $protocolloStats['totale'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Documenti non fattura nello stabile attivo.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Con PDF</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $protocolloStats['con_pdf'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Apribili in anteprima o stampa.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Questo mese</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $protocolloStats['questo_mese'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Nuovi inserimenti recenti.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Categorie</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $protocolloStats['categorie'] ?? 0 }}</div>
|
|
<div class="mt-1 text-sm text-slate-500">Tipologie disponibili nei filtri.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="flex flex-col gap-3 xl:flex-row xl:items-end xl:justify-between">
|
|
<div class="grid flex-1 gap-3 md:grid-cols-[minmax(0,1.4fr)_minmax(220px,0.6fr)]">
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Ricerca</label>
|
|
<input type="text" wire:model.live.debounce.300ms="protocolloSearch" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Protocollo, titolo, descrizione, ente, riferimento archivio..." />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Categoria</label>
|
|
<select wire:model.live="protocolloCategory" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
<option value="">Tutte le categorie</option>
|
|
@foreach($this->protocolloComunicazioniCategoryOptions as $categoryKey => $categoryLabel)
|
|
<option value="{{ $categoryKey }}">{{ $categoryLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2">
|
|
<button
|
|
type="button"
|
|
wire:click="setProtocolloView('cards')"
|
|
@class([
|
|
'rounded-full px-3 py-2 text-sm font-medium transition',
|
|
'bg-slate-900 text-white' => $this->protocolloView === 'cards',
|
|
'bg-slate-100 text-slate-600 hover:bg-slate-200' => $this->protocolloView !== 'cards',
|
|
])
|
|
>
|
|
Box
|
|
</button>
|
|
<button
|
|
type="button"
|
|
wire:click="setProtocolloView('list')"
|
|
@class([
|
|
'rounded-full px-3 py-2 text-sm font-medium transition',
|
|
'bg-slate-900 text-white' => $this->protocolloView === 'list',
|
|
'bg-slate-100 text-slate-600 hover:bg-slate-200' => $this->protocolloView !== 'list',
|
|
])
|
|
>
|
|
Lista
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if($this->protocolloView === 'cards')
|
|
<div class="grid gap-4 md:grid-cols-2 2xl:grid-cols-3">
|
|
@forelse($this->protocolloComunicazioniRows as $row)
|
|
<article class="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
|
|
<div class="aspect-[4/3] border-b border-slate-200 bg-slate-100">
|
|
@if($row['has_pdf'])
|
|
<iframe
|
|
src="{{ $row['preview_url'] }}#toolbar=0&navpanes=0&scrollbar=0"
|
|
class="h-full w-full"
|
|
loading="lazy"
|
|
title="Anteprima {{ $row['protocollo'] }}"
|
|
></iframe>
|
|
@else
|
|
<div class="flex h-full items-center justify-center px-6 text-center text-sm text-slate-500">
|
|
Anteprima PDF non disponibile per questo protocollo.
|
|
</div>
|
|
@endif
|
|
</div>
|
|
<div class="space-y-3 p-4">
|
|
<div class="flex flex-wrap items-center gap-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-slate-700">{{ $row['protocollo'] }}</span>
|
|
<span>{{ $row['categoria'] }}</span>
|
|
<span>{{ $row['data'] }}</span>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-slate-900">{{ $row['titolo'] }}</h3>
|
|
<p class="mt-1 text-sm text-slate-600">{{ $row['descrizione'] !== '' ? $row['descrizione'] : 'Nessuna descrizione registrata.' }}</p>
|
|
</div>
|
|
<div class="space-y-1 text-xs text-slate-500">
|
|
<div>Cartella: {{ $row['cartella'] }}</div>
|
|
@if($row['fornitore'] !== '')
|
|
<div>Ente / referente: {{ $row['fornitore'] }}</div>
|
|
@endif
|
|
@if($row['archive_reference'] !== '')
|
|
<div>Rif. archivio: {{ $row['archive_reference'] }}</div>
|
|
@endif
|
|
</div>
|
|
<div class="flex flex-wrap gap-2 pt-1">
|
|
<a href="{{ $row['preview_url'] }}" target="_blank" class="inline-flex items-center rounded-lg bg-slate-900 px-3 py-2 text-xs font-medium text-white hover:bg-slate-800">Apri</a>
|
|
<a href="{{ $row['download_url'] }}" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-medium text-slate-700 hover:bg-slate-50">Scarica</a>
|
|
@if($row['has_pdf'])
|
|
<a href="{{ $row['print_url'] }}" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-medium text-slate-700 hover:bg-slate-50">Stampa</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</article>
|
|
@empty
|
|
<div class="rounded-xl border border-dashed border-slate-300 bg-white px-4 py-10 text-sm text-slate-500 md:col-span-2 2xl:col-span-3">
|
|
Nessun documento protocollato trovato con i filtri correnti.
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
@else
|
|
<div class="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
|
|
<div class="grid grid-cols-[160px_minmax(0,1.4fr)_180px_130px] gap-3 border-b border-slate-200 bg-slate-50 px-4 py-3 text-xs font-semibold uppercase tracking-wide text-slate-500">
|
|
<div>Protocollo</div>
|
|
<div>Documento</div>
|
|
<div>Categoria / cartella</div>
|
|
<div>Azioni</div>
|
|
</div>
|
|
<div class="divide-y divide-slate-200">
|
|
@forelse($this->protocolloComunicazioniRows as $row)
|
|
<div class="grid grid-cols-[160px_minmax(0,1.4fr)_180px_130px] gap-3 px-4 py-3 text-sm text-slate-700">
|
|
<div>
|
|
<div class="font-semibold text-slate-900">{{ $row['protocollo'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $row['data'] }}</div>
|
|
</div>
|
|
<div class="min-w-0">
|
|
<div class="truncate font-semibold text-slate-900">{{ $row['titolo'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $row['descrizione'] !== '' ? $row['descrizione'] : 'Nessuna descrizione registrata.' }}</div>
|
|
@if($row['archive_reference'] !== '')
|
|
<div class="mt-1 text-xs text-sky-700">{{ $row['archive_reference'] }}</div>
|
|
@endif
|
|
</div>
|
|
<div>
|
|
<div class="font-medium text-slate-900">{{ $row['categoria'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $row['cartella'] }}</div>
|
|
</div>
|
|
<div class="flex flex-wrap gap-2">
|
|
<a href="{{ $row['preview_url'] }}" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-2.5 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-50">Apri</a>
|
|
@if($row['has_pdf'])
|
|
<a href="{{ $row['print_url'] }}" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-2.5 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-50">Stampa</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="px-4 py-8 text-sm text-slate-500">Nessun documento protocollato trovato con i filtri correnti.</div>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-filament::section>
|
|
@elseif($this->hubTab === 'archivio-digitale')
|
|
<x-filament::section>
|
|
<x-slot name="heading">Archivio digitale</x-slot>
|
|
<x-slot name="description">Navigazione a cartelle per lo stabile attivo: root stabile, cartella fatture_PDF, anno di arrivo. Le azioni restano operative ma visibili solo come icone.</x-slot>
|
|
|
|
<div class="space-y-4">
|
|
<div class="rounded-xl border border-slate-200 bg-slate-50 p-4">
|
|
<div class="flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between">
|
|
<div>
|
|
<div class="text-xs font-semibold uppercase tracking-[0.18em] text-slate-500">Percorso corrente</div>
|
|
<div class="mt-2 flex flex-wrap items-center gap-2 text-sm text-slate-700">
|
|
@foreach($this->digitalArchiveBreadcrumbs as $crumb)
|
|
<button
|
|
type="button"
|
|
wire:click="openDigitalFolder({{ $crumb['folder_id'] === null ? 'null' : $crumb['folder_id'] }})"
|
|
class="rounded-full border border-slate-200 bg-white px-3 py-1.5 font-medium text-slate-700 transition hover:border-sky-300 hover:text-sky-700"
|
|
>
|
|
{{ $crumb['label'] }}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
<div class="rounded-lg border border-sky-100 bg-white px-4 py-3 text-xs text-slate-600">
|
|
Nomi file fatture ordinati per data e protocollo, cosi la ricerca e l'elenco restano leggibili anche senza aprire il PDF.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
|
|
@forelse($this->digitalArchiveFolders as $folder)
|
|
<button
|
|
type="button"
|
|
wire:click="openDigitalFolder({{ $folder['id'] }})"
|
|
class="rounded-2xl border border-slate-200 bg-white p-4 text-left shadow-sm transition hover:-translate-y-0.5 hover:border-sky-300 hover:shadow"
|
|
>
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900">{{ $folder['nome'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $folder['descrizione'] }}</div>
|
|
</div>
|
|
<div class="rounded-full bg-sky-50 px-2.5 py-1 text-xs font-semibold text-sky-700">{{ $folder['conteggio'] }}</div>
|
|
</div>
|
|
</button>
|
|
@empty
|
|
<div class="rounded-xl border border-dashed border-slate-300 bg-white px-4 py-8 text-sm text-slate-500 md:col-span-2 xl:col-span-4">
|
|
Nessuna sottocartella disponibile nel livello corrente.
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
|
|
<div class="grid gap-3 lg:grid-cols-3">
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Cartella attiva</div>
|
|
<div class="mt-2 text-sm font-semibold text-slate-900">{{ $this->digitalArchiveCurrentFolder?->nome ?? 'Nessuna cartella selezionata' }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $this->digitalArchiveCurrentFolderHint }}</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Documenti nel livello</div>
|
|
<div class="mt-2 text-2xl font-semibold text-slate-900">{{ $this->digitalArchiveCurrentFolderDocumentCount }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">Solo fatture PDF collegate alla cartella corrente.</div>
|
|
</div>
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-xs uppercase tracking-wide text-slate-500">Operatività</div>
|
|
<div class="mt-2 text-sm font-semibold text-slate-900">Archivio digitale e fisico allineati</div>
|
|
<div class="mt-1 text-xs text-slate-500">Da qui puoi aprire, stampare, watermarkare e assegnare subito la collocazione cartacea.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
{{ $this->table }}
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
@elseif($this->hubTab === 'template-drive')
|
|
<x-filament::section>
|
|
<x-slot name="heading">Template cartelle Drive</x-slot>
|
|
<x-slot name="description">Questa struttura resta la base comune per archivio digitale, passaggio consegne e futura sincronizzazione Google.</x-slot>
|
|
|
|
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
|
|
@foreach($this->driveTemplateFolders as $folder)
|
|
<div class="rounded-xl border bg-slate-50 px-4 py-3 text-sm text-slate-700">{{ $folder }}</div>
|
|
@endforeach
|
|
</div>
|
|
</x-filament::section>
|
|
@elseif($this->hubTab === 'archivio-fisico')
|
|
<x-filament::section>
|
|
<x-slot name="heading">Archivio fisico</x-slot>
|
|
<x-slot name="description">Registro operativo del cartaceo: inserimento manuale, contenitori annidati, movimentazione per codice e stampa etichette 11354 o 99014.</x-slot>
|
|
|
|
<div class="grid gap-4 xl:grid-cols-[minmax(0,1.25fr)_minmax(0,0.75fr)]">
|
|
<div class="space-y-4">
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="flex items-center justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900">Elenco archivio condominiale</div>
|
|
<div class="mt-1 text-xs text-slate-500">Inserimento manuale come ticket: data, voce, titolo, nota, contenitore iniziale e posizione finale.</div>
|
|
</div>
|
|
<div class="rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-700">DB operativo</div>
|
|
</div>
|
|
|
|
<div class="mt-4 grid gap-3 md:grid-cols-2">
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Data</label>
|
|
<input type="date" wire:model.defer="physicalArchiveForm.data_archiviazione" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Voce archivio</label>
|
|
<select wire:model.live="physicalArchiveForm.voce_numero" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
<option value="">Seleziona voce</option>
|
|
@foreach($this->archivioObbligatorioRows as $row)
|
|
<option value="{{ $row['numero'] }}">Voce {{ $row['numero'] }} · {{ $row['titolo'] }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="md:col-span-2">
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Titolo da archiviare</label>
|
|
<input type="text" wire:model.defer="physicalArchiveForm.titolo" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. Contratto ascensore ORONA 2024" />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Tipologia elemento</label>
|
|
<select wire:model.live="physicalArchiveForm.tipo_item" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
@foreach($this->physicalArchiveTypeOptions as $typeKey => $typeLabel)
|
|
<option value="{{ $typeKey }}">{{ $typeLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Supporto iniziale</label>
|
|
<select wire:model.defer="physicalArchiveForm.supporto_fisico" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
<option value="">Nessun supporto</option>
|
|
@foreach($this->archivioFisicoTypes as $type)
|
|
<option value="{{ $type }}">{{ $type }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Documento digitale collegato</label>
|
|
<select wire:model.defer="physicalArchiveForm.documento_id" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
<option value="">Nessun documento digitale</option>
|
|
@foreach($this->physicalArchiveDocumentOptions as $documentId => $documentLabel)
|
|
<option value="{{ $documentId }}">{{ $documentLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Contenitore padre</label>
|
|
<select wire:model.defer="physicalArchiveForm.parent_id" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
<option value="">Radice archivio</option>
|
|
@foreach($this->physicalArchiveParentOptions as $parentId => $parentLabel)
|
|
<option value="{{ $parentId }}">{{ $parentLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Etichetta</label>
|
|
<select wire:model.defer="physicalArchiveForm.modello_etichetta" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
@foreach($this->getModelliEtichettaOptions() as $labelKey => $labelText)
|
|
<option value="{{ $labelKey }}">{{ $labelText }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="md:col-span-2">
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Nota</label>
|
|
<textarea wire:model.defer="physicalArchiveForm.note" rows="3" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Elenco fogli, riferimento verbale, contenuto della busta..."></textarea>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Magazzino</label>
|
|
<input type="text" wire:model.defer="physicalArchiveForm.magazzino" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. Sede EUR" />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Scaffale</label>
|
|
<input type="text" wire:model.defer="physicalArchiveForm.scaffale" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. A3" />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Ripiano</label>
|
|
<input type="text" wire:model.defer="physicalArchiveForm.ripiano" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. 2" />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Dettaglio ubicazione</label>
|
|
<input type="text" wire:model.defer="physicalArchiveForm.ubicazione_dettaglio" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. lato finestra" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex flex-wrap gap-2">
|
|
<button type="button" wire:click="savePhysicalArchiveEntry" class="inline-flex items-center rounded-lg bg-slate-900 px-4 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-slate-800">Registra voce fisica</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="flex items-center justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900">Movimentazione per codice</div>
|
|
<div class="mt-1 text-xs text-slate-500">Scansioni o inserisci il codice sorgente e il contenitore di arrivo per spostare intere buste o faldoni.</div>
|
|
</div>
|
|
</div>
|
|
<div class="mt-4 grid gap-3 md:grid-cols-2">
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Codice sorgente</label>
|
|
<input type="text" wire:model.defer="physicalArchiveMoveForm.source_code" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. AF-20-0001" />
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Codice destinazione</label>
|
|
<input type="text" wire:model.defer="physicalArchiveMoveForm.target_code" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Es. AF-20-0010" />
|
|
</div>
|
|
</div>
|
|
<div class="mt-4 flex flex-wrap gap-2">
|
|
<button type="button" wire:click="movePhysicalArchiveItem" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 shadow-sm transition hover:border-slate-400 hover:bg-slate-50">Registra movimentazione</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-sm font-semibold text-slate-900">Contenitori di primo livello</div>
|
|
<div class="mt-3 grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
@forelse($this->physicalArchiveContainerTree as $item)
|
|
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-3">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900">{{ $item['codice_univoco'] }}</div>
|
|
<div class="mt-1 text-sm text-slate-700">{{ $item['titolo'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $item['tipo'] }} · {{ $item['children_count'] }} elementi interni</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="rounded-lg border border-dashed border-slate-300 bg-white px-4 py-6 text-sm text-slate-500 sm:col-span-2 xl:col-span-3">Nessun contenitore creato ancora per lo stabile attivo.</div>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="space-y-4">
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="text-sm font-semibold text-slate-900">Standard etichette</div>
|
|
<div class="mt-3 space-y-3 text-sm text-slate-600">
|
|
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-3">Modelli attivi: <span class="font-semibold text-slate-900">11354</span> e <span class="font-semibold text-slate-900">99014</span>.</div>
|
|
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-3">Formato suggerito: <span class="font-semibold text-slate-900">{{ $this->mnemonicCodeHint ?? 'STB00000' }}</span> · contenuto · anno · busta · fascicolo.</div>
|
|
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-3">QR in stampa su etichetta e predisposizione NFC per scatole e fascicoli.</div>
|
|
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-3">Formato data archivio: <span class="font-semibold text-slate-900">AAAA-MM-GG</span> o <span class="font-semibold text-slate-900">YYYYMMDD</span> per aggancio automatico ai file gia codificati.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-xl border bg-white p-4">
|
|
<div class="flex items-center justify-between gap-3">
|
|
<div class="text-sm font-semibold text-slate-900">Registro e ricerca</div>
|
|
<div class="text-xs text-slate-500">Titolo manuale, ricerca testuale, contenimento annidato</div>
|
|
</div>
|
|
<div class="mt-3 grid gap-3 md:grid-cols-2">
|
|
<input type="text" wire:model.live.debounce.300ms="physicalArchiveSearch" class="w-full rounded-lg border-slate-200 text-sm shadow-sm" placeholder="Cerca per titolo, codice, nota..." />
|
|
<select wire:model.live="physicalArchiveTypeFilter" class="w-full rounded-lg border-slate-200 text-sm shadow-sm">
|
|
<option value="">Tutte le tipologie</option>
|
|
@foreach($this->physicalArchiveTypeOptions as $typeKey => $typeLabel)
|
|
<option value="{{ $typeKey }}">{{ $typeLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="mt-4 space-y-3">
|
|
@forelse($this->physicalArchiveRows as $row)
|
|
<div class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-3">
|
|
<div class="flex flex-col gap-3 xl:flex-row xl:items-start xl:justify-between">
|
|
<div class="min-w-0">
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<span class="rounded-full bg-slate-900 px-2.5 py-1 text-[11px] font-semibold text-white">{{ $row['codice_univoco'] }}</span>
|
|
<span class="rounded-full bg-white px-2.5 py-1 text-[11px] font-medium text-slate-700">{{ $row['tipo'] }}</span>
|
|
<span class="text-xs text-slate-500">{{ $row['data_archiviazione'] }}</span>
|
|
</div>
|
|
<div class="mt-2 text-sm font-semibold text-slate-900">{{ $row['titolo'] }}</div>
|
|
@if($row['voce'] !== '')
|
|
<div class="mt-1 text-xs text-slate-500">{{ $row['voce'] }}</div>
|
|
@endif
|
|
<div class="mt-1 text-xs text-slate-500">Dentro: {{ $row['parent'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">Percorso: {{ $row['percorso'] }}</div>
|
|
@if($row['ubicazione'] !== '')
|
|
<div class="mt-1 text-xs text-slate-500">Ubicazione: {{ $row['ubicazione'] }}</div>
|
|
@endif
|
|
@if($row['documento'])
|
|
<div class="mt-1 text-xs text-sky-700">Digitale collegato: {{ $row['documento'] }}</div>
|
|
@endif
|
|
</div>
|
|
<div class="flex shrink-0 flex-wrap items-center gap-2">
|
|
<a href="{{ route('filament.archivio-fisico.etichetta', ['item' => $row['id']]) }}?format=11354&autoprint=1&dymo_fix=0&dymo_rot=0&dymo_dx=0&dymo_dy=-1" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-medium text-slate-700 shadow-sm hover:bg-slate-50">11354</a>
|
|
<a href="{{ route('filament.archivio-fisico.etichetta', ['item' => $row['id']]) }}?format=11354&autoprint=1&dymo_fix=1&dymo_rot=90&dymo_dx=0&dymo_dy=0" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-medium text-slate-700 shadow-sm hover:bg-slate-50">11354 verticale</a>
|
|
<a href="{{ route('filament.archivio-fisico.etichetta', ['item' => $row['id']]) }}?format=99014&autoprint=1&dymo_fix=0&dymo_rot=0&dymo_dx=3.5&dymo_dy=3.5" target="_blank" class="inline-flex items-center rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-medium text-slate-700 shadow-sm hover:bg-slate-50">99014</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="rounded-lg border border-dashed border-slate-300 bg-white px-4 py-6 text-sm text-slate-500">Nessuna voce archivio fisico trovata con i filtri correnti.</div>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-amber-200 bg-amber-50 p-4">
|
|
<div class="text-sm font-semibold text-amber-900">Uso operativo</div>
|
|
<div class="mt-2 text-sm text-amber-800">Puoi registrare direttamente un pezzo di carta senza scansione, poi metterlo in una busta etichettata, spostare la busta in un faldone e il faldone in una scatola usando solo i codici stampati.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
@else
|
|
<x-filament::section>
|
|
<x-slot name="heading">Permessi e visibilita</x-slot>
|
|
<x-slot name="description">Qui prepariamo la classificazione dei documenti per audience e le cartelle visibili solo a ruoli, gruppi o utenti selezionati.</x-slot>
|
|
|
|
<div class="grid gap-4 xl:grid-cols-[minmax(0,1.3fr)_minmax(280px,0.7fr)]">
|
|
<div>
|
|
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
|
|
@foreach($this->visibleFolderRows as $folder)
|
|
<div class="rounded-xl border bg-white px-4 py-3">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-900">{{ $folder['nome'] }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">{{ $folder['stabile'] }}</div>
|
|
</div>
|
|
<div class="rounded-full bg-slate-100 px-2 py-1 text-[11px] font-medium text-slate-700">{{ $folder['scope'] }}</div>
|
|
</div>
|
|
<div class="mt-2 text-xs text-slate-600">{{ $folder['path'] }}</div>
|
|
<div class="mt-3 text-xs text-slate-500">Documenti collegati: {{ $folder['documents_count'] }}</div>
|
|
<div class="mt-2 text-xs text-slate-500">Ruoli: {{ $folder['roles'] !== [] ? implode(', ', $folder['roles']) : 'nessun filtro' }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">Gruppi: {{ $folder['groups'] !== [] ? implode(', ', $folder['groups']) : 'nessun filtro' }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">Utenti: {{ $folder['users'] !== [] ? implode(', ', $folder['users']) : 'nessun utente specifico' }}</div>
|
|
</div>
|
|
@endforeach
|
|
@if(empty($this->visibleFolderRows))
|
|
<div class="rounded-xl border border-dashed bg-white px-4 py-6 text-sm text-slate-500 md:col-span-2 xl:col-span-3">Nessuna cartella archivio configurata per lo stabile attivo. Usa “Nuova cartella archivio” per iniziare a separare visibilita e struttura.</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-3">
|
|
@foreach($this->audienceGroups as $group)
|
|
<div class="rounded-xl border bg-white px-4 py-3">
|
|
<div class="text-sm font-semibold text-slate-900">{{ $group }}</div>
|
|
<div class="mt-1 text-xs text-slate-500">Audience candidata per visibilita documentale, export e portali dedicati.</div>
|
|
</div>
|
|
@endforeach
|
|
<div class="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-xs text-amber-800">
|
|
Le cartelle ristrette sono applicate sia nella lista documenti sia nei download diretti, cosi l'ID del file non bypassa i permessi dello stabile o della cartella.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
</div>
|
|
</x-filament-panels::page> |