Initial commit

This commit is contained in:
2026-07-03 16:37:12 +07:00
commit 63b8c1ea8b
1931 changed files with 640587 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
@using RobotNet10.RobotApp.Client.Shared.Devices
@using Microsoft.AspNetCore.Components
@using MudBlazor
<MudCard Elevation="1" Class="mb-2">
<MudCardContent Class="pa-2">
@* Compact Header *@
<MudStack Row="true" AlignItems="@AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="1" Class="mb-1">
<MudStack Row="true" AlignItems="@AlignItems.Center" Spacing="1">
<MudIcon Icon="@GetDeviceIcon()" Color="@GetStatusColor()" Size="Size.Small" />
<div>
<MudText Typo="Typo.body2" Style="font-weight: 600; line-height: 1.2;">@Device.DeviceName</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary" Style="line-height: 1;">@Device.DeviceId</MudText>
</div>
</MudStack>
<MudStack Row="true" AlignItems="@AlignItems.Center" Spacing="1">
<MudChip T="string" Size="Size.Small" Color="@GetStatusColor()" Variant="Variant.Filled" Style="font-size: 0.7rem;">
@Device.Status.ToString()
</MudChip>
<MudIconButton Icon="@Icons.Material.Filled.Settings"
Size="Size.Small"
Color="Color.Primary"
Variant="Variant.Text"
OnClick="NavigateToDeviceManagement"
title="Manage Device" />
</MudStack>
</MudStack>
@* Compact Info Grid - 2 columns *@
<MudGrid Spacing="1" Class="mt-1">
@* Device Type *@
<MudItem xs="6">
<MudStack Row="true" AlignItems="@AlignItems.Center" Spacing="1">
<MudText Typo="Typo.caption" Color="Color.Secondary" Style="min-width: 60px;">Type:</MudText>
<MudChip T="string" Size="Size.Small" Variant="Variant.Text" Style="font-size: 0.7rem; height: 20px;">@Device.DeviceType</MudChip>
</MudStack>
</MudItem>
@* Connection Status *@
<MudItem xs="6">
<MudStack Row="true" AlignItems="@AlignItems.Center" Spacing="1">
<MudText Typo="Typo.caption" Color="Color.Secondary" Style="min-width: 60px;">Status:</MudText>
<MudIcon Icon="@(Device.IsConnected ? Icons.Material.Filled.CheckCircle : Icons.Material.Filled.Cancel)"
Color="@(Device.IsConnected ? Color.Success : Color.Error)"
Size="Size.Small" Style="width: 16px; height: 16px;" />
<MudText Typo="Typo.caption">@(Device.IsConnected ? "Yes" : "No")</MudText>
</MudStack>
</MudItem>
@* Last Update - Compact format *@
<MudItem xs="12">
<MudStack Row="true" AlignItems="@AlignItems.Center" Spacing="1">
<MudText Typo="Typo.caption" Color="Color.Secondary" Style="min-width: 60px;">Updated:</MudText>
<MudText Typo="Typo.caption">@Device.LastUpdateTime.ToString("MM-dd HH:mm:ss")</MudText>
</MudStack>
</MudItem>
@* Reconnect Attempts - Only show if > 0 *@
@if (Device.ReconnectAttemptCount > 0)
{
<MudItem xs="12">
<MudStack Row="true" AlignItems="@AlignItems.Center" Spacing="1">
<MudText Typo="Typo.caption" Color="Color.Secondary" Style="min-width: 60px;">Retries:</MudText>
<MudChip T="int" Size="Size.Small" Color="Color.Warning" Style="font-size: 0.7rem; height: 20px;">@Device.ReconnectAttemptCount</MudChip>
</MudStack>
</MudItem>
}
</MudGrid>
@* Error Message - Compact *@
@if (!string.IsNullOrWhiteSpace(Device.LastError))
{
<MudAlert Severity="Severity.Error" Dense="true" Class="mt-1" Style="padding: 4px 8px;">
<MudText Typo="Typo.caption" Style="line-height: 1.2;">@Device.LastError</MudText>
</MudAlert>
}
@* Properties - Collapsed by default, only show count *@
@if (Device.Properties.Any())
{
<MudExpansionPanels Dense="true" Class="mt-1">
<MudExpansionPanel Text="@($"Properties ({Device.Properties.Count})")" Icon="@Icons.Material.Filled.Info" Style="font-size: 0.75rem;">
<MudSimpleTable Dense="true" Style="font-size: 0.7rem;">
<thead>
<tr>
<th style="padding: 4px;">Property</th>
<th style="padding: 4px;">Value</th>
</tr>
</thead>
<tbody>
@foreach (var prop in GetDisplayedProperties().Take(5))
{
<tr>
<td style="padding: 2px 4px;">
<MudText Typo="Typo.caption">@prop.DisplayName</MudText>
</td>
<td style="padding: 2px 4px;">
@if (Device.Properties.TryGetValue(prop.Key, out var value))
{
<MudText Typo="Typo.caption">
@FormatPropertyValue(value, prop)
</MudText>
}
</td>
</tr>
}
@if (Device.Properties.Count > 5)
{
<tr>
<td colspan="2" style="padding: 2px 4px; text-align: center;">
<MudText Typo="Typo.caption" Color="Color.Secondary">
... and @(Device.Properties.Count - 5) more
</MudText>
</td>
</tr>
}
</tbody>
</MudSimpleTable>
</MudExpansionPanel>
</MudExpansionPanels>
}
</MudCardContent>
</MudCard>
@code {
[Parameter, EditorRequired]
public DeviceDto Device { get; set; } = null!;
[Inject]
private NavigationManager NavigationManager { get; set; } = null!;
private void NavigateToDeviceManagement()
{
var deviceType = GetDeviceTypeRoute(Device.DeviceType);
var deviceId = Uri.EscapeDataString(Device.DeviceId);
NavigationManager.NavigateTo($"/devices/{deviceType}/{deviceId}");
}
private string GetDeviceTypeRoute(DeviceType deviceType)
{
return deviceType switch
{
DeviceType.Lidar => "lidar",
DeviceType.Imu => "imu",
DeviceType.Battery => "battery",
DeviceType.ModbusTcp => "modbustcp",
DeviceType.RfHandle => "rfhandle",
DeviceType.CameraQr => "cameraqr",
DeviceType.CiA402Servo => "cia402servo",
_ => deviceType.ToString().ToLowerInvariant()
};
}
private string GetDeviceIcon()
{
return Device.DeviceType switch
{
DeviceType.Lidar => Icons.Material.Filled.Radar,
DeviceType.Imu => Icons.Material.Filled.Explore,
DeviceType.Battery => Icons.Material.Filled.BatteryFull,
DeviceType.ModbusTcp => Icons.Material.Filled.Lan,
DeviceType.RfHandle => Icons.Material.Filled.RadioButtonChecked,
DeviceType.CameraQr => Icons.Material.Filled.QrCodeScanner,
DeviceType.CiA402Servo => Icons.Material.Filled.Settings,
_ => Icons.Material.Filled.Devices
};
}
private Color GetStatusColor()
{
return Device.Status switch
{
DeviceStatus.Connected => Color.Success,
DeviceStatus.Connecting => Color.Info,
DeviceStatus.Disconnecting => Color.Warning,
DeviceStatus.Disconnected => Color.Default,
DeviceStatus.Reconnecting => Color.Warning,
DeviceStatus.Error => Color.Error,
DeviceStatus.Initializing => Color.Info,
_ => Color.Default
};
}
private IEnumerable<PropertyDescription> GetDisplayedProperties()
{
return Device.PropertyDescriptions
.OrderBy(p => p.DisplayOrder)
.ThenBy(p => p.Category ?? "")
.ThenBy(p => p.DisplayName);
}
private string FormatPropertyValue(string value, PropertyDescription prop)
{
if (string.IsNullOrWhiteSpace(value))
return "-";
if (prop.DataType == "number" && double.TryParse(value, out var numValue))
{
if (!string.IsNullOrWhiteSpace(prop.Format))
{
try
{
return string.Format(prop.Format, numValue) + (prop.Unit != null ? $" {prop.Unit}" : "");
}
catch
{
return value + (prop.Unit != null ? $" {prop.Unit}" : "");
}
}
return value + (prop.Unit != null ? $" {prop.Unit}" : "");
}
return value + (prop.Unit != null ? $" {prop.Unit}" : "");
}
}