@page "/ispezione" @using Microsoft.Extensions.Logging @using SteUp.Shared.Components.Layout @using SteUp.Shared.Components.Layout.Overlay @using SteUp.Shared.Components.SingleElements.Card @using SteUp.Shared.Components.SingleElements.MessageBox @using SteUp.Shared.Core.Dto @using SteUp.Shared.Core.Entities @using SteUp.Shared.Core.Enum @using SteUp.Shared.Core.Interface.IntegryApi @using SteUp.Shared.Core.Interface.LocalDb @using SteUp.Shared.Core.Interface.System @using SteUp.Shared.Core.Messages.Ispezione @using SteUp.Shared.Core.Messages.Scheda @inject NewSchedaService NewScheda @inject CompleteInspectionService CompleteInspection @inject IIspezioniService IspezioniService @inject IDialogService Dialog @inject IIntegrySteupService IntegrySteupService @inject IFileManager FileManager @inject ILogger Logger @implements IDisposable
@if (!SchedeGrouped.IsNullOrEmpty()) { @{ var panelIndex = 0; } @foreach (var group in SchedeGrouped) { var isFirstPanel = panelIndex == 0; panelIndex++; @{ var daInviare = group.Value.CountDaInviare(); }
@group.Key.Descrizione @($"{group.Value.Count} sched{(group.Value.Count == 1 ? "a" : "e")}") @if (daInviare > 0) { @($"{daInviare} da inviare") }
@if (SteupDataService.InspectionPageState.Ispezione.Stato != StatusEnum.Completata) {
@if (NetworkService.IsNetworkAvailable() && daInviare > 0) { }
}
@foreach (var scheda in group.Value) { }
}
} else {

Nessuna scheda ancora

@if (SteupDataService.InspectionPageState.Ispezione.Stato != StatusEnum.Completata) {

Tocca + in basso per creare la prima scheda di questa ispezione.

}
}
@code { private List SchedeList { get; set; } = []; private Dictionary> SchedeGrouped { get; set; } = []; private bool VisibleOverlay { get; set; } private bool _isBusy; private bool _success; private string? _progressMessage; private ConfirmMessageBox _exportRepartoBox = null!; protected override void OnInitialized() { NewScheda.OnNewScheda += LoadSchede; CompleteInspection.OnComplete += HandleCompleteInspection; LoadSchede(); } private void LoadSchede() { var ispezione = SteupDataService.InspectionPageState.Ispezione; InvokeAsync(async () => { SchedeList = await IspezioniService.GetAllSchedeOfIspezioneAsync( ispezione.CodMdep, ispezione.Data, ispezione.Rilevatore ); GroupSchede(); StateHasChanged(); }); } private async void HandleCompleteInspection() { // Guardia anti doppio-invio: il completamento è irreversibile. if (_isBusy) return; _isBusy = true; try { await InvokeAsync(() => { VisibleOverlay = true; StateHasChanged(); }); var ispezione = SteupDataService.InspectionPageState.Ispezione; var daInviare = ispezione.Schede.Where(x => x.ActivityId == null).ToList(); var totale = daInviare.Count; var indice = 0; var fallite = 0; foreach (var scheda in daInviare) { indice++; await SetProgress($"Invio scheda {indice} di {totale}…"); var apiResponse = await IntegrySteupService.SaveScheda( new SaveRequestDto { LocalIdScheda = scheda.Id, ActivityTypeId = scheda.ActivityTypeId, CodJfas = scheda.CodJfas, CodMdep = ispezione.CodMdep, DataCreazione = ispezione.Data, Note = scheda.Note, PersonaRif = scheda.Responsabile, Barcodes = scheda.Articoli.ConvertAll(x => x.Barcode), Scandeza = (ScadenzaEnum)scheda.Scadenza, // Aggancia all'ispezione esistente: dopo la prima scheda l'id e' noto, // così le successive non creano nuove ispezioni. ParentActivityId = ispezione.ActivityId } ); // Fallita: resta "Da inviare". Non completeremo l'ispezione finché tutte non sono arrivate. if (apiResponse == null) { fallite++; continue; } scheda.ActivityId = apiResponse.ActivityIdScheda; await IspezioniService.UpdateSchedaAsync(scheda); await IspezioniService.UpdateActivityIdIspezioneAsync( ispezione.CodMdep, ispezione.Data, ispezione.Rilevatore, apiResponse.ActivityIdIspezione ); // Aggiorna l'id in memoria per l'iterazione successiva. ispezione.ActivityId = apiResponse.ActivityIdIspezione; if (scheda.ImageNames == null) continue; var fileList = (await FileManager.GetInspectionFiles(ispezione, scheda.ImageNames))? .Where(x => x.ToUpload).ToList(); if (fileList == null) continue; var totFoto = fileList.Count; var indiceFoto = 0; foreach (var file in fileList) { indiceFoto++; await SetProgress($"Scheda {indice}/{totale} · foto {indiceFoto}/{totFoto}…"); await IntegrySteupService.UploadFile(scheda.ActivityId!, file.FileBytes!, file.Name!); } } // Integrità dati: se anche una sola scheda non è arrivata al server, NON completare. // L'ispezione resta editabile e le schede fallite restano "Da inviare". if (fallite > 0) { await InvokeAsync(() => { _progressMessage = null; StateHasChanged(); }); LoadSchede(); // rinfresca i badge: riuscite → "Inviato", fallite → restano "Da inviare" await Dialog.ShowWarning( fallite == 1 ? "1 scheda non è stata inviata e resta salvata sul dispositivo. Controlla la connessione e riprova prima di concludere l'ispezione." : $"{fallite} schede non sono state inviate e restano salvate sul dispositivo. Controlla la connessione e riprova prima di concludere l'ispezione." ); return; } await SetProgress("Completamento ispezione…"); await IntegrySteupService.CompleteInspection(ispezione.ActivityId!); await IspezioniService.UpdateStatoIspezioneAsync( ispezione.CodMdep, ispezione.Data, ispezione.Rilevatore, StatusEnum.Completata ); SteupDataService.InspectionPageState.Ispezione.Stato = StatusEnum.Completata; // Riscontro al momento più importante: la spunta di successo prima di chiudere l'overlay. await InvokeAsync(() => { _progressMessage = "Ispezione inviata"; _success = true; StateHasChanged(); }); await Task.Delay(1800); } catch (Exception e) { OnError(e, e.Message); } finally { _isBusy = false; _success = false; _progressMessage = null; await InvokeAsync(() => { VisibleOverlay = false; StateHasChanged(); }); } } private Task SetProgress(string message) => InvokeAsync(() => { _progressMessage = message; StateHasChanged(); }); private void GroupSchede() { SchedeGrouped = SchedeList .Where(s => s.Reparto != null) .GroupBy(s => s.CodJfas) .ToDictionary( g => g.First().Reparto!, g => g.ToList() ); } private void OnSchedaModified(Scheda obj) { var index = SchedeList.FindIndex(x => x.Id.Equals(obj.Id)); if (index >= 0) SchedeList[index] = obj; GroupSchede(); StateHasChanged(); } private void OnSchedaDeleted(Scheda obj) { SchedeList.Remove(obj); GroupSchede(); StateHasChanged(); } private async Task CreateNewScheda(JtbFasiDto jtbFasi) { var modal = await Dialog.OpenFormScheda( SteupDataService.InspectionPageState.Ispezione.CodMdep, SteupDataService.InspectionPageState.Ispezione.Data, true, new Scheda { Reparto = jtbFasi } ); if (modal is { Canceled: false }) LoadSchede(); } private async Task ExportReparto(JtbFasiDto jtbFasi) { // Guardia anti doppio-tap: un secondo tocco durante l'invio non ri-esporta il batch. if (_isBusy) return; var confirmed = await _exportRepartoBox.ShowAsync(); if (confirmed is not true) return; _isBusy = true; VisibleOverlay = true; StateHasChanged(); try { var ispezione = SteupDataService.InspectionPageState.Ispezione; var saveRequest = SchedeGrouped[jtbFasi].ConvertAll(x => { return new SaveRequestDto { LocalIdScheda = x.Id, ActivityTypeId = x.ActivityTypeId, CodJfas = x.CodJfas, CodMdep = ispezione.CodMdep, DataCreazione = ispezione.Data, Note = x.Note, PersonaRif = x.Responsabile, Barcodes = x.Articoli.ConvertAll(y => y.Barcode), Scandeza = (ScadenzaEnum)x.Scadenza, // Aggancia all'ispezione esistente sul server (evita di crearne una nuova a ogni export). ParentActivityId = ispezione.ActivityId }; }); var apiResponse = await IntegrySteupService.SaveMultipleSchede(saveRequest); if (apiResponse == null) { Snackbar.Add("Esportazione non riuscita. Le schede restano sul dispositivo, riprova.", Severity.Error); return; } SteupDataService.InspectionPageState.Ispezione.ActivityId = apiResponse.ActivityIdIspezione; await IspezioniService.UpdateActivityIdIspezioneAsync(ispezione.CodMdep, ispezione.Data, UserSession.User.Username, apiResponse.ActivityIdIspezione ); if (!apiResponse.ActivityIdSchedaList.IsNullOrEmpty()) { foreach (var scheda in SchedeGrouped[jtbFasi]) { var activityId = apiResponse.ActivityIdSchedaList!.Find(x => x.LocalId != null && x.LocalId == scheda.Id )?.ActivityId; if (activityId == null) continue; scheda.ActivityId = activityId; await IspezioniService.UpdateActivityIdSchedaAsync(scheda.Id, scheda.ActivityId); } } Snackbar.Add("Reparto esportato", Severity.Success); } catch (Exception e) { OnError(e, e.Message); } finally { _isBusy = false; VisibleOverlay = false; StateHasChanged(); } } private void OnError(Exception? e, string? technicalMessage) { // Il dettaglio tecnico va nei log, non davanti al rilevatore in campo. if (e != null) Logger.LogError(e, technicalMessage); _ = Dialog.ShowError( "Invio non riuscito. Il lavoro resta salvato sul dispositivo: controlla la connessione e riprova." ); } void IDisposable.Dispose() { NewScheda.OnNewScheda -= LoadSchede; CompleteInspection.OnComplete -= HandleCompleteInspection; } }