421 lines
16 KiB
Plaintext
421 lines
16 KiB
Plaintext
@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<IspezionePage> Logger
|
|
@implements IDisposable
|
|
|
|
<HeaderLayout Title="Ispezione" BackTo="Indietro" Back="true"/>
|
|
|
|
<div class="container content pb-safe-area ispezione">
|
|
<InspectionCard Ispezione="SteupDataService.InspectionPageState.Ispezione"/>
|
|
|
|
@if (!SchedeGrouped.IsNullOrEmpty())
|
|
{
|
|
<MudExpansionPanels MultiExpansion="true">
|
|
@{
|
|
var panelIndex = 0;
|
|
}
|
|
@foreach (var group in SchedeGrouped)
|
|
{
|
|
var isFirstPanel = panelIndex == 0;
|
|
panelIndex++;
|
|
<MudExpansionPanel Class="expansion-panel" Expanded="isFirstPanel" Text="@group.Key.Descrizione">
|
|
<TitleContent>
|
|
@{
|
|
var daInviare = group.Value.CountDaInviare();
|
|
}
|
|
<div class="header-scheda-group">
|
|
<div class="title">
|
|
<MudText Typo="Typo.h6"><b>@group.Key.Descrizione</b></MudText>
|
|
<MudChip T="string" Size="Size.Small" Color="Color.Default">
|
|
@($"{group.Value.Count} sched{(group.Value.Count == 1 ? "a" : "e")}")
|
|
</MudChip>
|
|
@if (daInviare > 0)
|
|
{
|
|
<MudChip T="string" Size="Size.Small" Variant="Variant.Filled"
|
|
Color="Color.Primary" Icon="@Icons.Material.Rounded.PhonelinkOff">
|
|
@($"{daInviare} da inviare")
|
|
</MudChip>
|
|
}
|
|
</div>
|
|
@if (SteupDataService.InspectionPageState.Ispezione.Stato != StatusEnum.Completata)
|
|
{
|
|
<div class="action-scheda-group">
|
|
<MudFab StartIcon="@Icons.Material.Rounded.Add"
|
|
Color="Color.Default" Size="Size.Medium"
|
|
Disabled="!NetworkService.IsNetworkAvailable()"
|
|
aria-label="@($"Nuova scheda su {group.Key.Descrizione}")"
|
|
OnClick="@(() => CreateNewScheda(group.Key))"/>
|
|
|
|
@if (NetworkService.IsNetworkAvailable() && daInviare > 0)
|
|
{
|
|
<MudFab StartIcon="@Icons.Material.Rounded.CloudUpload" Label="Esporta reparto"
|
|
Color="Color.Primary" Size="Size.Medium"
|
|
aria-label="@($"Esporta il reparto {group.Key.Descrizione} al server")"
|
|
OnClick="@(() => ExportReparto(group.Key))"/>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</TitleContent>
|
|
<ChildContent>
|
|
@foreach (var scheda in group.Value)
|
|
{
|
|
<SchedaCard Scheda="scheda" OnSchedaDeleted="OnSchedaDeleted"
|
|
OnSchedaModified="OnSchedaModified"
|
|
Ispezione="@SteupDataService.InspectionPageState.Ispezione"/>
|
|
}
|
|
</ChildContent>
|
|
</MudExpansionPanel>
|
|
}
|
|
</MudExpansionPanels>
|
|
}
|
|
else
|
|
{
|
|
<div class="empty-state">
|
|
<MudIcon Icon="@Icons.Material.Rounded.AssignmentLate" Class="empty-state-icon" Size="Size.Large"/>
|
|
<p class="empty-state-title">Nessuna scheda ancora</p>
|
|
@if (SteupDataService.InspectionPageState.Ispezione.Stato != StatusEnum.Completata)
|
|
{
|
|
<p class="empty-state-text">
|
|
Tocca <b>+</b> in basso per creare la prima scheda di questa ispezione.
|
|
</p>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<SpinnerOverlay VisibleOverlay="VisibleOverlay" SuccessAnimation="_success" Message="@_progressMessage"/>
|
|
<ConfirmMessageBox @ref="_exportRepartoBox" NoText="Annulla" YesText="Esporta" YesColor="Color.Primary"
|
|
Message="Le schede di questo reparto verranno inviate al server. Procedere?"/>
|
|
|
|
@code {
|
|
private List<Scheda> SchedeList { get; set; } = [];
|
|
private Dictionary<JtbFasiDto, List<Scheda>> 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;
|
|
}
|
|
|
|
} |