- Pagina scanner
This commit is contained in:
@ -0,0 +1,31 @@
|
||||
@inject Radzen.DialogService DialogService
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p>Benvenuto <strong>@RagioneSociale</strong>.</p>
|
||||
<p class="text-secondary">Confermare la presenza?</p>
|
||||
|
||||
<div class="mb-3">
|
||||
<RadzenLabel Text="Numero Partecipanti" Component="Partecipanti" Style="margin-bottom: 5px;" />
|
||||
<RadzenNumeric Name="Partecipanti" @bind-Value="Partecipanti" Min="1" Style="width: 100%" />
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<button type="button" class="btn btn-primary w-100" @onclick="(() => DialogService.Close(Partecipanti))">
|
||||
Conferma
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<button type="button" class="btn btn-default w-100" @onclick="(() => DialogService.Close(null))">
|
||||
Annulla
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string RagioneSociale { get; set; }
|
||||
[Parameter] public int Partecipanti { get; set; }
|
||||
}
|
||||
@ -1,21 +1,28 @@
|
||||
@page "/activate-qr-scan"
|
||||
@using StandManager.Components.Layout
|
||||
@using Microsoft.JSInterop
|
||||
@implements IAsyncDisposable
|
||||
@inject NavigationManager Nav
|
||||
@layout PublicLayout
|
||||
|
||||
@inject IJSRuntime JS
|
||||
@inject BodyClassService BodyClass
|
||||
@inject Radzen.DialogService _dialogService
|
||||
@inject IManagerService _managerService
|
||||
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Scan Code</PageTitle>
|
||||
|
||||
<RadzenDialog />
|
||||
|
||||
<div class="page" style="min-height: 100dvh;">
|
||||
<div class="page-wrapper" style="min-height: 100dvh;">
|
||||
<div class="container container-tight py-4 d-flex flex-column" style="min-height: 100dvh;">
|
||||
|
||||
<!-- Top bar -->
|
||||
<div class="d-flex align-items-center justify-content-between pt-4">
|
||||
<button type="button"
|
||||
class="btn btn-icon btn-ghost-secondary rounded-circle"
|
||||
class="btn btn-action"
|
||||
aria-label="Chiudi"
|
||||
@onclick="OnClose">
|
||||
<i class="fa fa-x footer-icon"></i>
|
||||
@ -24,7 +31,7 @@
|
||||
<div class="flex-fill"></div>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-icon btn-ghost-secondary rounded-circle"
|
||||
class="btn btn-action"
|
||||
aria-label="Aiuto"
|
||||
@onclick="OnHelp">
|
||||
<i class="fa fa-question footer-icon"></i>
|
||||
@ -37,11 +44,15 @@
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
<RadzenTextBox @bind-Value="@registrationCode" Placeholder="Inserirci il codice" Style="width: 100%;" />
|
||||
@if (!string.IsNullOrEmpty(invalidCode))
|
||||
{
|
||||
<div class="text-danger mt-1">@invalidCode</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(invalidCode))
|
||||
{
|
||||
<div class="alert alert-danger w-100">
|
||||
<strong>Errore:</strong> @invalidCode
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="col-6 mb-3">
|
||||
<button type="button" class="btn btn-primary w-100" @onclick="GoTo">
|
||||
Invia
|
||||
@ -56,16 +67,53 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Bottom actions -->
|
||||
@if (openScan)
|
||||
{
|
||||
<div class="d-flex flex-column align-items-center justify-content-center text-center flex-fill px-3">
|
||||
<div class="mb-3 w-100">
|
||||
<div style="position: relative; width: 100%; max-width: 400px; margin: 0 auto;">
|
||||
<video @ref="videoRef" autoplay playsinline class="w-100 rounded border border-2 border-primary" style="aspect-ratio: 1/1; object-fit: cover;"></video>
|
||||
|
||||
<div style="position: absolute; top: 10%; left: 10%; right: 10%; bottom: 10%; border: 2px dashed rgba(255,255,255,0.8); border-radius: 12px; pointer-events: none;"></div>
|
||||
</div>
|
||||
|
||||
<p class="text-secondary mt-3">Inquadra il QR Code</p>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(invalidCode))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-11">
|
||||
<div class="alert alert-danger w-100">
|
||||
<strong>Errore:</strong> @invalidCode
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<button type="button"
|
||||
class="btn btn-action"
|
||||
aria-label="Chiudi"
|
||||
@onclick="RefreshScan">
|
||||
<i class="fa-solid fa-arrows-rotate footer-icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="mt-3">
|
||||
<button type="button" class="btn btn-default" @onclick="StopScanAndClose">
|
||||
Ferma Scansione
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!openManual && !openScan)
|
||||
{
|
||||
<!-- Center content -->
|
||||
<div class="d-flex flex-column align-items-center justify-content-center text-center flex-fill px-3">
|
||||
<div class="mb-5">
|
||||
<div class="qr-shell">
|
||||
<span class="ti ti-qrcode qr-icon"></span>
|
||||
|
||||
<!-- corner accents -->
|
||||
<span class="qr-corner tl"></span>
|
||||
<span class="qr-corner tr"></span>
|
||||
<span class="qr-corner bl"></span>
|
||||
@ -108,16 +156,25 @@
|
||||
@code {
|
||||
[Parameter] public EventCallback Close { get; set; }
|
||||
[Parameter] public EventCallback Help { get; set; }
|
||||
[Parameter] public EventCallback Scan { get; set; }
|
||||
[Parameter] public EventCallback Manual { get; set; }
|
||||
|
||||
private bool openManual { get; set; } = false;
|
||||
private bool openScan { get; set; } = false;
|
||||
private string registrationCode { get; set; }
|
||||
private string invalidCode = string.Empty;
|
||||
private string registrationCode { get; set; } = string.Empty;
|
||||
private string invalidCode { get; set; } = string.Empty;
|
||||
|
||||
// Scanner
|
||||
private ElementReference videoRef;
|
||||
private DotNetObjectReference<object>? objRef;
|
||||
private bool isScanning;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
objRef = DotNetObjectReference.Create<object>(this);
|
||||
}
|
||||
|
||||
private async Task OnClose()
|
||||
{
|
||||
if (isScanning) await StopScan();
|
||||
Nav.NavigateTo("/");
|
||||
}
|
||||
|
||||
@ -125,32 +182,142 @@
|
||||
{
|
||||
}
|
||||
|
||||
private async Task OnScan()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task OnManual()
|
||||
private void OnManual()
|
||||
{
|
||||
openManual = true;
|
||||
invalidCode = string.Empty;
|
||||
}
|
||||
|
||||
private async Task GoTo()
|
||||
{
|
||||
var code = Guid.Empty;
|
||||
|
||||
if (Guid.TryParse(registrationCode, out code))
|
||||
if (Guid.TryParse(registrationCode, out var code))
|
||||
{
|
||||
var iscrizione = await _managerService.IscrizioneEventoService.RicercaPer(filtro: x => x.Id == code);
|
||||
var iscrizione = await _managerService.IscrizioneEventoService.RicercaPer(filtro: x => x.Id == code, solaLettura: false);
|
||||
|
||||
var ok = await _dialogService.Confirm($"Il numero di persone indicate per questo evento è {iscrizione.Partecipanti}", $"Benvenuto {iscrizione.RagioneSociale}", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
|
||||
if (iscrizione != null)
|
||||
{
|
||||
invalidCode = string.Empty;
|
||||
|
||||
var result = await _dialogService.OpenAsync<Component_Conferma_Iscrizione>("Conferma Numero Partecipanti",
|
||||
new Dictionary<string, object>() {
|
||||
{ "RagioneSociale", iscrizione.RagioneSociale },
|
||||
{ "Partecipanti", iscrizione.Partecipanti }
|
||||
},
|
||||
new DialogOptions() { Width = "400px", CloseDialogOnOverlayClick = false }
|
||||
);
|
||||
|
||||
if (result == null) await Reset();
|
||||
|
||||
var numPartecipanti = (int)result;
|
||||
|
||||
iscrizione.ScanCompleto = true;
|
||||
iscrizione.DataScan = DateTime.Now;
|
||||
iscrizione.Partecipanti = numPartecipanti;
|
||||
await _managerService.IscrizioneEventoService.Salva(iscrizione);
|
||||
|
||||
await Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
invalidCode = "Codice non trovato.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invalidCode = "Il codice inserito non risulta corretto!";
|
||||
}
|
||||
else invalidCode = "Il codice inserito non risulta corretto!";
|
||||
}
|
||||
|
||||
private async Task UndoChoice()
|
||||
{
|
||||
openManual = false;
|
||||
registrationCode = string.Empty;
|
||||
await StopScan();
|
||||
openScan = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnScan()
|
||||
{
|
||||
openScan = true;
|
||||
// Delay per crazione tag <video>
|
||||
await Task.Delay(100);
|
||||
await StartScan();
|
||||
}
|
||||
|
||||
private async Task StartScan()
|
||||
{
|
||||
if (isScanning) return;
|
||||
|
||||
try
|
||||
{
|
||||
isScanning = true;
|
||||
await JS.InvokeVoidAsync("qrScanner.start", videoRef, objRef);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
invalidCode = "Impossibile avviare la fotocamera: " + ex.Message;
|
||||
isScanning = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StopScanAndClose()
|
||||
{
|
||||
await StopScan();
|
||||
openScan = false;
|
||||
}
|
||||
|
||||
private async Task StopScan()
|
||||
{
|
||||
if (!isScanning) return;
|
||||
|
||||
isScanning = false;
|
||||
await JS.InvokeVoidAsync("qrScanner.stop", videoRef);
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task OnQrDecoded(string text)
|
||||
{
|
||||
await StopScan();
|
||||
registrationCode = text;
|
||||
|
||||
await GoTo();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public Task OnQrError(string message)
|
||||
{
|
||||
invalidCode = message;
|
||||
isScanning = false;
|
||||
StateHasChanged();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (isScanning)
|
||||
{
|
||||
await StopScan();
|
||||
}
|
||||
|
||||
objRef?.Dispose();
|
||||
}
|
||||
|
||||
private async Task RefreshScan()
|
||||
{
|
||||
invalidCode = string.Empty;
|
||||
await OnScan();
|
||||
}
|
||||
|
||||
private async Task Reset()
|
||||
{
|
||||
registrationCode = string.Empty;
|
||||
invalidCode = string.Empty;
|
||||
|
||||
openManual = false;
|
||||
openScan = false;
|
||||
|
||||
await StopScan();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user