Initial commit
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
@implements IAsyncDisposable
|
||||
|
||||
@using MudBlazor
|
||||
@using Microsoft.AspNetCore.SignalR.Client
|
||||
@using RobotNet10.RobotApp.Client.Clients
|
||||
@using RobotNet10.RobotApp.Client.Shared.Devices
|
||||
|
||||
@inject CameraQrHubClient CameraQrHubClient
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h5">@DeviceName</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">@DeviceId</MudText>
|
||||
</CardHeaderContent>
|
||||
<CardHeaderActions>
|
||||
<MudTooltip Text="Reload Camera QR data">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Refresh"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small"
|
||||
OnClick="ReloadCameraQrDataAsync"
|
||||
Disabled="@(!CameraQrHubClient.IsConnected || IsReloading)">
|
||||
</MudIconButton>
|
||||
</MudTooltip>
|
||||
</CardHeaderActions>
|
||||
</MudCardHeader>
|
||||
<MudCardContent Style="position: relative;" Class="pa-2">
|
||||
<MudGrid Spacing="2">
|
||||
<!-- Left Column: Camera Frame Visualization -->
|
||||
<MudItem xs="12" md="6">
|
||||
<MudCard Elevation="0" Class="pa-2">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary" Class="mb-2">Camera Frame</MudText>
|
||||
<div class="d-flex flex-column align-center justify-center" style="height: 100%; width: 100%; position: relative;">
|
||||
<svg width="100%" height="100%" viewBox="0 0 640 480" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" style="max-height: 400px; border: 2px solid var(--mud-palette-divider); border-radius: 4px;">
|
||||
<defs>
|
||||
<!-- Gradient cho camera frame -->
|
||||
<linearGradient id="@($"cameraGradient_{DeviceId}")" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#1a1a1a;stop-opacity:1" />
|
||||
<stop offset="50%" style="stop-color:#2a2a2a;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#1a1a1a;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<!-- Filter cho glow effect -->
|
||||
<filter id="@($"glow_{DeviceId}")">
|
||||
<feGaussianBlur stdDeviation="3" result="coloredBlur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Camera frame background -->
|
||||
<rect x="0" y="0" width="640" height="480" fill="url(@($"#cameraGradient_{DeviceId}"))" />
|
||||
|
||||
</svg>
|
||||
</div>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
|
||||
<!-- Right Column: Data -->
|
||||
<MudItem xs="12" md="6">
|
||||
<MudGrid Spacing="1">
|
||||
<!-- Connection Status -->
|
||||
<MudItem xs="12">
|
||||
<MudCard Elevation="0" Class="pa-2">
|
||||
<MudGrid Spacing="1">
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudChip T="string" Color="@(CameraQrData.IsConnected ? Color.Success : Color.Error)"
|
||||
Size="Size.Small"
|
||||
Variant="Variant.Filled">
|
||||
@(CameraQrData.IsConnected ? "Connected" : "Disconnected")
|
||||
</MudChip>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
|
||||
<!-- Detection Status -->
|
||||
<MudItem xs="12">
|
||||
<MudCard Elevation="0" Class="pa-2">
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary" Class="mb-1">Detection Status</MudText>
|
||||
<MudGrid Spacing="1">
|
||||
<MudItem xs="12">
|
||||
@if (CameraQrData.Codes is { Count: > 0 })
|
||||
{
|
||||
<MudTable Dense="true" Hover="true" Bordered="true" Elevation="0" Items="CameraQrData.Codes">
|
||||
<HeaderContent>
|
||||
<MudTh>Code</MudTh>
|
||||
<MudTh>X (m)</MudTh>
|
||||
<MudTh>Y (m)</MudTh>
|
||||
<MudTh>Z (m)</MudTh>
|
||||
<MudTh>Yaw (deg)</MudTh>
|
||||
<MudTh>Time</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate Context="kv">
|
||||
<MudTd>@kv.Key</MudTd>
|
||||
<MudTd>@kv.Value.Pose.Position.X.ToString("F3")</MudTd>
|
||||
<MudTd>@kv.Value.Pose.Position.Y.ToString("F3")</MudTd>
|
||||
<MudTd>@kv.Value.Pose.Position.Z.ToString("F3")</MudTd>
|
||||
<MudTd>@kv.Value.Pose.Orientation.ToYawDegrees().ToString("F1")</MudTd>
|
||||
<MudTd>@kv.Value.Header.Stamp.ToLocalTime().ToString("HH:mm:ss")</MudTd>
|
||||
</RowTemplate>
|
||||
<FooterContent>
|
||||
<MudTd ColSpan="6">
|
||||
Total: @CameraQrData.Codes.Count code(s)
|
||||
</MudTd>
|
||||
</FooterContent>
|
||||
</MudTable>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">
|
||||
No QR detected.
|
||||
</MudText>
|
||||
}
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
|
||||
</MudGrid>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
|
||||
<MudOverlay Visible="@IsLoading" Absolute="true">
|
||||
<MudProgressCircular Indeterminate="true" Size="Size.Large" />
|
||||
</MudOverlay>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired]
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
private string DeviceName { get; set; } = string.Empty;
|
||||
private CameraQrDataDto CameraQrData = new();
|
||||
private bool IsLoading => !CameraQrHubClient.IsConnected;
|
||||
private bool IsReloading = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender && !string.IsNullOrEmpty(DeviceId))
|
||||
{
|
||||
await ConnectAsync();
|
||||
}
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
private async Task ConnectAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await CameraQrHubClient.StartAsync();
|
||||
|
||||
// Lấy DeviceName từ CameraQrHub
|
||||
var deviceInfo = await CameraQrHubClient.GetDeviceInfoAsync(DeviceId);
|
||||
if (deviceInfo != null)
|
||||
{
|
||||
DeviceName = deviceInfo.DeviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
DeviceName = DeviceId; // Fallback to DeviceId if not found
|
||||
}
|
||||
|
||||
CameraQrData = await CameraQrHubClient.GetCameraQrDataAsync(DeviceId);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Failed to connect: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DisconnectAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await CameraQrHubClient.StopAsync();
|
||||
CameraQrData = new CameraQrDataDto(); // Reset về giá trị mặc định
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Failed to disconnect: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReloadCameraQrDataAsync()
|
||||
{
|
||||
if (!CameraQrHubClient.IsConnected || IsReloading)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
IsReloading = true;
|
||||
StateHasChanged();
|
||||
|
||||
CameraQrData = await CameraQrHubClient.GetCameraQrDataAsync(DeviceId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Failed to reload Camera QR data: {ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsReloading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetConfidenceColor(double confidence)
|
||||
{
|
||||
if (confidence >= 0.9)
|
||||
{
|
||||
return Color.Success;
|
||||
}
|
||||
else if (confidence >= 0.7)
|
||||
{
|
||||
return Color.Info;
|
||||
}
|
||||
else if (confidence >= 0.5)
|
||||
{
|
||||
return Color.Warning;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.Error;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await DisconnectAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user