311 lines
12 KiB
Plaintext
311 lines
12 KiB
Plaintext
@implements IAsyncDisposable
|
|
|
|
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
|
@using RobotNet.WebApp.Clients
|
|
|
|
@inject RobotHubClient RobotHub
|
|
@inject ISnackbar Snackbar
|
|
@inject IHttpClientFactory HttpFactory
|
|
|
|
<MudCard Class="w-100 me-2 position-relative" Elevation="0" Outlined Style="height: 450px">
|
|
<MudCardHeader>
|
|
<MudText Typo="Typo.h5">Setting</MudText>
|
|
<MudSpacer />
|
|
<MudText Typo="Typo.subtitle1">@Robot.Name</MudText>
|
|
</MudCardHeader>
|
|
<MudCardContent>
|
|
<div class="d-flex flex-column">
|
|
<div class="d-flex flex-row my-2">
|
|
<div class="d-flex flex-row" style="width: 350px">
|
|
<MudAutocomplete T="MapInfoDto" Variant="Variant.Outlined" Label="Map" ShrinkLabel Disabled="!Robot.Online" Modal SearchFunc="MapSearch"
|
|
ToStringFunc="@(e=> e == null ? null : $"{e.Name}")" MaxItems="Maps.Count" ValueChanged="MapChanged" ShowProgressIndicator="true">
|
|
<NoItemsTemplate>
|
|
<MudText Align="Align.Center" Class="px-4 py-1">
|
|
No items found
|
|
</MudText>
|
|
</NoItemsTemplate>
|
|
</MudAutocomplete>
|
|
</div>
|
|
<MudButton Class="d-flex flex-grow-1 mt-2 mb-1 ms-2" Variant="Variant.Filled" Color="Color.Info" Disabled="!Robot.Online" OnClick="SetMap">SetMap</MudButton>
|
|
</div>
|
|
<div class="d-flex flex-row my-2">
|
|
<div class="d-flex flex-row" style="width: 350px">
|
|
<MudAutocomplete T="string" Variant="Variant.Outlined" Label="Node" ShrinkLabel Disabled="!Robot.Online" Modal SearchFunc="NodeSearch" ShowProgressIndicator="true"
|
|
MaxItems="@Nodes.Count" ValueChanged="NodeChanged">
|
|
<NoItemsTemplate>
|
|
<MudText Align="Align.Center" Class="px-4 py-1">
|
|
No items found
|
|
</MudText>
|
|
</NoItemsTemplate>
|
|
</MudAutocomplete>
|
|
<MudButton Class="ms-2 mt-2 mb-1" Variant="Variant.Filled" Color="Color.Info" Disabled="@(!Robot.Online || IsWorking)" OnClick="MoveToNode">Move</MudButton>
|
|
</div>
|
|
<MudButton Class="d-flex flex-grow-1 mt-2 mb-1 ms-2" Variant="Variant.Filled" Color="Color.Secondary" Disabled="@(!Robot.Online)" OnClick="CancelOrder">CancelOrder</MudButton>
|
|
</div>
|
|
<div class="d-flex flex-row my-2">
|
|
<div class="d-flex flex-row" style="width: 350px">
|
|
<MudAutocomplete T="ActionDto" Variant="Variant.Outlined" Label="Action" ShrinkLabel Disabled="!Robot.Online" Modal SearchFunc="ActionSearch" ShowProgressIndicator="true"
|
|
MaxItems="@Actions.Count" ValueChanged="ActionChanged" ToStringFunc="@(e=> e == null ? null : $"{e.Name}")">
|
|
<NoItemsTemplate>
|
|
<MudText Align="Align.Center" Class="px-4 py-1">
|
|
No items found
|
|
</MudText>
|
|
</NoItemsTemplate>
|
|
</MudAutocomplete>
|
|
<MudButton Class="ms-2 mt-2 mb-1" Variant="Variant.Filled" Color="Color.Info" Disabled="@(!Robot.Online || IsWorking)" OnClick="SendAction">Send</MudButton>
|
|
</div>
|
|
<MudButton Class="d-flex flex-grow-1 mt-2 mb-1 ms-2" Variant="Variant.Filled" Color="Color.Secondary" Disabled="@(!Robot.Online)" OnClick="CancelAction">CancelAction</MudButton>
|
|
</div>
|
|
<div class="d-flex flex-row my-2">
|
|
<div class="d-flex flex-row" style="width: 350px">
|
|
<MudNumericField T="double" Label="X(m)" Class="me-2" @bind-Value="InitPosition.X" Disabled="!Robot.Online" Variant="Variant.Outlined"></MudNumericField>
|
|
<MudNumericField T="double" Label="Y(m)" Class="me-2" @bind-Value="InitPosition.Y" Disabled="!Robot.Online" Variant="Variant.Outlined"></MudNumericField>
|
|
<MudNumericField T="double" Label="Theta(degree)" @bind-Value="InitPosition.Theta" Disabled="!Robot.Online" Variant="Variant.Outlined"></MudNumericField>
|
|
</div>
|
|
<MudButton Class="d-flex flex-grow-1 ms-2" Variant="Variant.Filled" Color="Color.Info" Disabled="!Robot.Online" OnClick="InitPose">InitPose</MudButton>
|
|
</div>
|
|
</div>
|
|
</MudCardContent>
|
|
|
|
<MudOverlay Visible="OverlayIsVisible" DarkBackground="true" Absolute="true">
|
|
<MudProgressCircular Color="Color.Secondary" Indeterminate="true" />
|
|
</MudOverlay>
|
|
</MudCard>
|
|
|
|
@code {
|
|
[Parameter, EditorRequired]
|
|
public RobotDto Robot { get; set; } = new();
|
|
|
|
private MapInfoDto MapSelected = default!;
|
|
private string SelectedNode = "";
|
|
|
|
private List<NodeDto> Nodes = [];
|
|
private List<MapInfoDto> Maps = [];
|
|
|
|
private (double X, double Y, double Theta) InitPosition = new();
|
|
private bool IsWorking = false;
|
|
private bool OverlayIsVisible;
|
|
|
|
private List<ActionDto> Actions = [];
|
|
private ActionDto? ActionSelected = null;
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
await base.OnAfterRenderAsync(firstRender);
|
|
if (!firstRender) return;
|
|
|
|
await RobotHub.StartAsync();
|
|
|
|
await LoadMaps();
|
|
}
|
|
|
|
public void UpdateState(bool isOnline, bool isWorking)
|
|
{
|
|
Robot.Online = isOnline;
|
|
IsWorking = isWorking;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task MoveToNode()
|
|
{
|
|
if (string.IsNullOrEmpty(SelectedNode))
|
|
{
|
|
Snackbar.Add("Vui lòng chọn node", Severity.Warning);
|
|
}
|
|
else
|
|
{
|
|
OverlayIsVisible = true;
|
|
StateHasChanged();
|
|
|
|
var result = await RobotHub.MoveToNode(Robot.RobotId, SelectedNode);
|
|
if (result.IsSuccess) Snackbar.Add("Ra lệnh thành công", Severity.Success);
|
|
else Snackbar.Add($"Ra lệnh không thành công: {result.Message}", Severity.Warning);
|
|
|
|
OverlayIsVisible = false;
|
|
}
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task CancelOrder()
|
|
{
|
|
OverlayIsVisible = true;
|
|
StateHasChanged();
|
|
|
|
var result = await RobotHub.CancelNavigation(Robot.RobotId);
|
|
if (result.IsSuccess) Snackbar.Add("Ra lệnh thành công", Severity.Success);
|
|
else Snackbar.Add($"Ra lệnh không thành công: {result.Message}", Severity.Warning);
|
|
|
|
OverlayIsVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task SetMap()
|
|
{
|
|
OverlayIsVisible = true;
|
|
StateHasChanged();
|
|
|
|
var result = await RobotHub.SetMap(Robot.RobotId, MapSelected.Id);
|
|
if (result.IsSuccess)
|
|
{
|
|
Robot.MapId = MapSelected.Id;
|
|
await LoadNodes();
|
|
await LoadActionAsync();
|
|
Snackbar.Add("Ra lệnh thành công", Severity.Success);
|
|
}
|
|
else Snackbar.Add($"Ra lệnh không thành công: {result.Message}", Severity.Warning);
|
|
|
|
OverlayIsVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task InitPose()
|
|
{
|
|
OverlayIsVisible = true;
|
|
StateHasChanged();
|
|
|
|
var result = await RobotHub.SetInitialPose(Robot.RobotId, InitPosition.X, InitPosition.Y, InitPosition.Theta * Math.PI / 180);
|
|
if (result.IsSuccess) Snackbar.Add("Ra lệnh thành công", Severity.Success);
|
|
else Snackbar.Add($"Ra lệnh không thành công: {result.Message}", Severity.Warning);
|
|
|
|
OverlayIsVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task SendAction()
|
|
{
|
|
if (ActionSelected is null)
|
|
{
|
|
Snackbar.Add("Vui lòng chọn action", Severity.Warning);
|
|
}
|
|
else
|
|
{
|
|
OverlayIsVisible = true;
|
|
StateHasChanged();
|
|
|
|
var result = await RobotHub.SendAction(Robot.RobotId, ActionSelected);
|
|
if (result.IsSuccess) Snackbar.Add("Ra lệnh thành công", Severity.Success);
|
|
else Snackbar.Add($"Ra lệnh không thành công: {result.Message}", Severity.Warning);
|
|
|
|
OverlayIsVisible = false;
|
|
}
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task CancelAction()
|
|
{
|
|
OverlayIsVisible = true;
|
|
StateHasChanged();
|
|
|
|
var result = await RobotHub.CancelAction(Robot.RobotId);
|
|
if (result.IsSuccess) Snackbar.Add("Ra lệnh thành công", Severity.Success);
|
|
else Snackbar.Add($"Ra lệnh không thành công: {result.Message}", Severity.Warning);
|
|
|
|
OverlayIsVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
public async Task LoadActionAsync()
|
|
{
|
|
Actions.Clear();
|
|
using var Http = HttpFactory.CreateClient("MapManagerAPI");
|
|
var result = await Http.GetFromJsonAsync<IEnumerable<ActionDto>>($"api/Actions/{Robot.MapId}");
|
|
|
|
if (result is not null && result.Any())
|
|
{
|
|
Actions.AddRange(result);
|
|
}
|
|
if (Actions.Any()) ActionSelected = Actions.First();
|
|
|
|
StateHasChanged();
|
|
}
|
|
|
|
public async Task LoadNodes()
|
|
{
|
|
try
|
|
{
|
|
using var Http = HttpFactory.CreateClient("MapManagerAPI");
|
|
var result = await Http.GetFromJsonAsync<NodeDto[]>($"api/Nodes/{Robot.MapId}");
|
|
if (result is not null) Nodes = result.Where(n => !string.IsNullOrEmpty(n.Name)).ToList();
|
|
}
|
|
catch (AccessTokenNotAvailableException ex)
|
|
{
|
|
ex.Redirect();
|
|
}
|
|
}
|
|
|
|
private async Task LoadMaps()
|
|
{
|
|
try
|
|
{
|
|
Maps.Clear();
|
|
using var Http = HttpFactory.CreateClient("MapManagerAPI");
|
|
var maps = await Http.GetFromJsonAsync<IEnumerable<MapInfoDto>>($"api/MapsManager?txtSearch=");
|
|
Maps.AddRange(maps ?? []);
|
|
StateHasChanged();
|
|
}
|
|
catch (AccessTokenNotAvailableException ex)
|
|
{
|
|
ex.Redirect();
|
|
return;
|
|
}
|
|
}
|
|
|
|
private async Task<IEnumerable<MapInfoDto>> MapSearch(string value, CancellationToken token)
|
|
{
|
|
await Task.Delay(5, token);
|
|
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
return Maps;
|
|
}
|
|
|
|
return Maps.Where(x => x.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase));
|
|
}
|
|
|
|
private async Task<IEnumerable<string>> NodeSearch(string value, CancellationToken token)
|
|
{
|
|
await Task.Delay(5, token);
|
|
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
return Nodes.Select(n => n.Name);
|
|
}
|
|
|
|
return Nodes.Where(x => x.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase)).Select(n => n.Name);
|
|
}
|
|
|
|
|
|
private async Task<IEnumerable<ActionDto>> ActionSearch(string value, CancellationToken token)
|
|
{
|
|
await Task.Delay(5, token);
|
|
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
return Actions;
|
|
}
|
|
|
|
return Actions.Where(x => x.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase));
|
|
}
|
|
|
|
private void NodeChanged(string value)
|
|
{
|
|
if (string.IsNullOrEmpty(SelectedNode) || value != SelectedNode) SelectedNode = value;
|
|
}
|
|
|
|
|
|
private void ActionChanged(ActionDto value)
|
|
{
|
|
if (ActionSelected is null || value.Id != ActionSelected.Id) ActionSelected = value;
|
|
}
|
|
|
|
private void MapChanged(MapInfoDto value)
|
|
{
|
|
if (MapSelected is null || value.Id != MapSelected.Id) MapSelected = value;
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await RobotHub.StopAsync();
|
|
}
|
|
}
|