Files
Denso/srcs/RobotNet10/FleetManager/RobotNet10.FleetManager.Client/Components/RobotDetail/ManualActionsPanel.razor
2026-07-03 16:31:37 +07:00

217 lines
7.7 KiB
Plaintext

@using RobotNet.VDA5050
@using RobotNet.VDA5050.Type
@using System.Net.Http.Json
@using RobotNet10.FleetManager.Shared.Models
@using RobotNet10.Shared
@inject HttpClient HttpClient
@inject ISnackbar Snackbar
<MudPaper Class="pa-4" Elevation="0">
<MudText Typo="Typo.h6" Class="mb-4">Manual Actions</MudText>
<MudStack Spacing="3">
<!-- Action Type Selector -->
<MudSelect @bind-Value="selectedActionType"
Label="Action Type"
Variant="Variant.Outlined"
T="ActionType">
@foreach (ActionType actionType in Enum.GetValues<ActionType>())
{
<MudSelectItem Value="@actionType">@actionType.ToString()</MudSelectItem>
}
</MudSelect>
<!-- Blocking Type Selector -->
<MudSelect @bind-Value="selectedBlockingType"
Label="Blocking Type"
Variant="Variant.Outlined"
T="BlockingType">
@foreach (BlockingType blockingType in Enum.GetValues<BlockingType>())
{
<MudSelectItem Value="@blockingType">@blockingType.ToString()</MudSelectItem>
}
</MudSelect>
<!-- Action Parameters -->
<MudText Typo="Typo.subtitle2">Action Parameters</MudText>
@foreach (var param in actionParameters)
{
<MudGrid>
<MudItem xs="5">
<MudTextField @bind-Value="param.Key"
Label="Key"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
</MudItem>
<MudItem xs="5">
<MudTextField @bind-Value="param.Value"
Label="Value"
Variant="Variant.Outlined"
Margin="Margin.Dense" />
</MudItem>
<MudItem xs="2">
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Color="Color.Error"
Size="Size.Small"
OnClick="@(() => RemoveParameter(param))" />
</MudItem>
</MudGrid>
}
<MudButton StartIcon="@Icons.Material.Filled.Add"
Variant="Variant.Outlined"
Color="Color.Primary"
OnClick="AddParameter">
Add Parameter
</MudButton>
<!-- Send Action Button -->
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Send"
OnClick="SendAction"
Disabled="@isSending"
FullWidth="true">
@if (isSending)
{
<MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
<span>Sending...</span>
}
else
{
<span>Send Action</span>
}
</MudButton>
<!-- Action History -->
<MudDivider />
<MudText Typo="Typo.subtitle2">Recent Actions</MudText>
@if (actionHistory.Count > 0)
{
<MudStack Spacing="1" Style="height: 200px; overflow-y: auto">
@foreach (var action in actionHistory.Take(10))
{
<MudPaper Class="pa-2" Elevation="0">
<MudText Typo="Typo.body2">
<strong>@action.ActionType</strong> - @action.Timestamp.ToString("g")
</MudText>
</MudPaper>
}
</MudStack>
}
else
{
<MudText Typo="Typo.body2" Align="Align.Center">No actions sent yet</MudText>
}
</MudStack>
</MudPaper>
@code {
[Parameter]
public string RobotId { get; set; } = string.Empty;
private ActionType selectedActionType = ActionType.STATE_REQUEST;
private BlockingType selectedBlockingType = BlockingType.HARD;
private List<RobotNet.VDA5050.InstantAction.ActionParameter> actionParameters = new();
private List<SentAction> actionHistory = new();
private bool isSending = false;
private class SentAction
{
public ActionType ActionType { get; set; }
public DateTime Timestamp { get; set; }
}
private void AddParameter()
{
actionParameters.Add(new RobotNet.VDA5050.InstantAction.ActionParameter());
}
private void RemoveParameter(RobotNet.VDA5050.InstantAction.ActionParameter param)
{
actionParameters.Remove(param);
}
private async Task SendAction()
{
if (string.IsNullOrWhiteSpace(RobotId))
{
Snackbar.Add("Robot ID is required", Severity.Warning);
return;
}
isSending = true;
StateHasChanged();
try
{
// Build action request
var actionRequest = new RobotInstantActionModel
{
RobotId = RobotId,
Action = new RobotNet.VDA5050.InstantAction.Action
{
ActionId = Guid.NewGuid().ToString(),
BlockingType = selectedBlockingType,
ActionType = selectedActionType.ToJsonString(),
ActionParameters = [.. actionParameters.Where(p => !string.IsNullOrWhiteSpace(p.Key))],
}
};
// Call API endpoint (TODO: Create this endpoint in Phase 10)
var response = await HttpClient.PostAsJsonAsync($"/api/robotManager/InstantActions", actionRequest);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadFromJsonAsync<MessageResult>();
if(result is null)
{
Snackbar.Add($"Sending action is failed", Severity.Warning);
}
else if (!result.IsSuccess)
{
Snackbar.Add($"{result.Message}", Severity.Warning);
}
else
{
Snackbar.Add($"Action '{selectedActionType}' sent successfully", Severity.Success);
// Add to history
actionHistory.Insert(0, new SentAction
{
ActionType = selectedActionType,
Timestamp = DateTime.UtcNow
});
// Clear parameters
actionParameters.Clear();
}
}
else if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Snackbar.Add($"Robot with ID '{RobotId}' not found", Severity.Error);
}
else if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var error = await response.Content.ReadAsStringAsync();
Snackbar.Add($"Invalid action request: {error}", Severity.Warning);
}
else
{
var error = await response.Content.ReadAsStringAsync();
Snackbar.Add($"Error sending action: {error}", Severity.Error);
}
}
catch (Exception ex)
{
Snackbar.Add($"Error sending action: {ex.Message}", Severity.Error);
}
finally
{
isSending = false;
StateHasChanged();
}
}
}