Initial commit

This commit is contained in:
2026-07-13 09:25:40 +07:00
parent c08ff54676
commit bccfb156d7
1938 changed files with 641646 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
@page "/maps"
@rendermode InteractiveWebAssemblyNoPrerender
@using MudBlazor
@using RobotNet10.RobotApp.Client.Shared.SLAM
@using RobotNet10.RobotApp.Client.Clients
@using RobotNet10.RobotApp.Client.Components.SLAM
@implements IAsyncDisposable
@inject SLAMClient CartographerClient
@inject ISnackbar Snackbar
@inject IDialogService DialogService
<PageTitle>Map Management</PageTitle>
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="mt-4">
<MudCard Elevation="2">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h5">Map Management</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Refresh"
OnClick="RefreshMapsAsync"
Disabled="@(!CartographerClient.IsConnected || IsLoading)">
Refresh
</MudButton>
</CardHeaderActions>
</MudCardHeader>
<MudCardContent>
@if (IsLoading)
{
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
}
else if (Maps.Count == 0)
{
<MudText Typo="Typo.body1" Color="Color.Secondary">
No maps found. Create a map by starting scan mapping.
</MudText>
}
else
{
<MudTable Items="@Maps" Hover="true" Striped="true">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Created</MudTh>
<MudTh>Resolution</MudTh>
<MudTh>Size</MudTh>
<MudTh>Trajectory Nodes</MudTh>
<MudTh></MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">
<MudText Typo="Typo.body1">@context.Name</MudText>
</MudTd>
<MudTd DataLabel="Created">
<MudText Typo="Typo.body2">@context.CreatedDate.ToString("yyyy-MM-dd HH:mm")</MudText>
</MudTd>
<MudTd DataLabel="Resolution">
<MudText Typo="Typo.body2">@context.Resolution.ToString("F3") m/p</MudText>
</MudTd>
<MudTd DataLabel="Size">
<MudText Typo="Typo.body2">@context.Width.ToString("F1") x @context.Height.ToString("F1") m</MudText>
</MudTd>
<MudTd DataLabel="Trajectory Nodes">
<MudText Typo="Typo.body2">@context.TrajectoryNodeCount</MudText>
</MudTd>
<MudTd DataLabel="Actions">
<MudTooltip Text="View map details">
<MudIconButton Icon="@Icons.Material.Filled.OpenInNew"
Color="Color.Primary"
Size="Size.Small"
Href="@($"/map/{context.Name}")" />
</MudTooltip>
</MudTd>
</RowTemplate>
</MudTable>
}
</MudCardContent>
</MudCard>
</MudContainer>
@code {
private List<MapInfoDto> Maps { get; set; } = new();
private bool IsLoading { get; set; } = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await CartographerClient.StartAsync();
await RefreshMapsAsync();
}
}
private async Task RefreshMapsAsync()
{
if (!CartographerClient.IsConnected)
{
Snackbar.Add("Not connected to server", Severity.Warning);
return;
}
try
{
IsLoading = true;
StateHasChanged();
Maps = (await CartographerClient.ListMapsAsync()).ToList();
}
catch (Exception ex)
{
Snackbar.Add($"Failed to load maps: {ex.Message}", Severity.Error);
}
finally
{
IsLoading = false;
StateHasChanged();
}
}
private async Task LoadMapAsync(string mapName)
{
try
{
var success = await CartographerClient.StartLocalizationAsync(mapName);
if (success)
{
Snackbar.Add($"Started localization with map: {mapName}", Severity.Success);
}
else
{
Snackbar.Add($"Failed to start localization with map: {mapName}", Severity.Error);
}
}
catch (Exception ex)
{
Snackbar.Add($"Failed to load map: {ex.Message}", Severity.Error);
}
}
private async Task DeleteMapAsync(string mapName)
{
var parameters = new DialogParameters
{
["MapName"] = mapName
};
var options = new DialogOptions
{
CloseOnEscapeKey = true,
MaxWidth = MaxWidth.Small,
FullWidth = true
};
var dialog = await DialogService.ShowAsync<DeleteMapDialog>("Delete Map", parameters, options);
var result = await dialog.Result;
if (result != null && !result.Canceled)
{
try
{
var success = await CartographerClient.DeleteMapAsync(mapName);
if (success)
{
Snackbar.Add($"Map deleted: {mapName}", Severity.Success);
await RefreshMapsAsync();
}
else
{
Snackbar.Add($"Failed to delete map: {mapName}", Severity.Error);
}
}
catch (Exception ex)
{
Snackbar.Add($"Failed to delete map: {ex.Message}", Severity.Error);
}
}
}
private string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
public async ValueTask DisposeAsync()
{
// CartographerClient is scoped, will be disposed by DI
}
}