Files
Denso/srcs/RobotNet10/RobotApp/RobotNet10.RobotApp.Client/Components/Motion/RotationModuleCard.razor
2026-07-03 16:31:37 +07:00

234 lines
9.0 KiB
Plaintext

@using RobotNet10.RobotApp.Client.Clients
@using RobotNet10.RobotApp.Client.Shared.Modules
@using MudBlazor
<MudPaper Class="pa-4" Style="height: 100%;">
<MudStack Spacing="3">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h5">Rotation Module</MudText>
<MudIconButton Icon="@Icons.Material.Filled.Refresh"
Color="Color.Primary"
Size="Size.Small"
OnClick="RefreshStatus"
Disabled="@(!IsHubReady || isLoading)" />
</MudStack>
@* Rotation Status Information *@
@if (rotationStatus != null)
{
<MudCard>
<MudCardContent>
<MudText Typo="Typo.h6" Class="mb-3">Module Status</MudText>
<MudStack Spacing="2">
<MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText>State:</MudText>
<MudChip T="string" Color="@GetStateColor(rotationStatus.State)" Size="Size.Small">
@rotationStatus.State
</MudChip>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText>Ready:</MudText>
<MudChip T="bool" Color="@(rotationStatus.IsReady ? Color.Success : Color.Default)" Size="Size.Small">
@rotationStatus.IsReady
</MudChip>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween">
<MudText>Current Angle:</MudText>
<MudText>@($"{rotationStatus.CurrentAngle:F2}°")</MudText>
</MudStack>
</MudStack>
</MudCardContent>
</MudCard>
}
@* Rotation Control Buttons *@
<MudStack Spacing="3">
<MudText Typo="Typo.h6">Rotation Controls</MudText>
@* Rotate to Absolute Angle *@
<MudStack Row="true" Spacing="3" AlignItems="@AlignItems.Center">
<MudNumericField @bind-Value="targetAngle"
Label="Target Angle (°)"
Variant="Variant.Outlined"
Class="flex-grow-1" />
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
OnClick="RotateToAngle"
Disabled="@(isLoading || !IsHubReady || rotationStatus?.IsReady != true)">
<MudIcon Icon="@Icons.Material.Filled.LocationOn" Class="mr-2" />
<MudText>Go</MudText>
</MudButton>
</MudStack>
@* Rotate Offset *@
<MudStack Row="true" Spacing="3" AlignItems="@AlignItems.Center">
<MudNumericField @bind-Value="angleOffset"
Label="Offset (°)"
Variant="Variant.Outlined"
HelperText="+/- for CW/CCW"
Class="flex-grow-1" />
<MudButton Variant="Variant.Filled"
Color="Color.Info"
OnClick="RotateOffset"
Disabled="@(isLoading || !IsHubReady || rotationStatus?.IsReady != true)">
<MudIcon Icon="@Icons.Material.Filled.RotateRight" Class="mr-2" />
<MudText>Offset</MudText>
</MudButton>
</MudStack>
@* Quick Rotation Buttons *@
<MudStack Row="true" Spacing="3" AlignItems="@AlignItems.Center" Wrap="Wrap.Wrap">
<MudButton Variant="Variant.Outlined"
Color="Color.Secondary"
OnClick="() => RotateOffsetQuick(-90)"
Disabled="@(isLoading || !IsHubReady || rotationStatus?.IsReady != true)">
<MudIcon Icon="@Icons.Material.Filled.RotateLeft" Class="mr-2" />
<MudText>-90°</MudText>
</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Secondary"
OnClick="() => RotateOffsetQuick(-45)"
Disabled="@(isLoading || !IsHubReady || rotationStatus?.IsReady != true)">
<MudIcon Icon="@Icons.Material.Filled.RotateLeft" Class="mr-2" />
<MudText>-45°</MudText>
</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Secondary"
OnClick="() => RotateOffsetQuick(45)"
Disabled="@(isLoading || !IsHubReady || rotationStatus?.IsReady != true)">
<MudIcon Icon="@Icons.Material.Filled.RotateRight" Class="mr-2" />
<MudText>+45°</MudText>
</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Secondary"
OnClick="() => RotateOffsetQuick(90)"
Disabled="@(isLoading || !IsHubReady || rotationStatus?.IsReady != true)">
<MudIcon Icon="@Icons.Material.Filled.RotateRight" Class="mr-2" />
<MudText>+90°</MudText>
</MudButton>
</MudStack>
</MudStack>
</MudStack>
</MudPaper>
@code {
[Parameter, EditorRequired] public MotionHubClient HubClient { get; set; } = null!;
[Parameter] public bool IsHubReady { get; set; }
[Inject] private ISnackbar Snackbar { get; set; } = null!;
private RotationModuleStatusDto? rotationStatus;
private bool isLoading = false;
private double targetAngle = 0;
private double angleOffset = 0;
private bool _previousIsHubReady = false;
protected override async Task OnParametersSetAsync()
{
// Detect when IsHubReady changes from false to true
if (IsHubReady && !_previousIsHubReady)
{
await RefreshStatus();
}
_previousIsHubReady = IsHubReady;
}
public async Task RefreshStatus()
{
if (isLoading || !IsHubReady) return;
try
{
isLoading = true;
rotationStatus = await HubClient.GetRotationStatusAsync();
StateHasChanged();
}
catch (Exception ex)
{
Snackbar.Add($"Error refreshing rotation status: {ex.Message}", Severity.Error);
}
finally
{
isLoading = false;
}
}
private Color GetStateColor(string state)
{
return state switch
{
"Ready" => Color.Success,
"Moving" => Color.Info,
"Error" => Color.Error,
"Homing" => Color.Warning,
"Initializing" => Color.Warning,
_ => Color.Default
};
}
private async Task RotateToAngle()
{
if (!IsHubReady || isLoading || rotationStatus?.IsReady != true)
return;
try
{
isLoading = true;
Snackbar.Add($"Rotating to angle {targetAngle}°...", Severity.Info);
await HubClient.RotateToAngleAsync(targetAngle);
Snackbar.Add($"Rotate to angle {targetAngle}° command sent successfully", Severity.Success);
await Task.Delay(500);
await RefreshStatus();
}
catch (Exception ex)
{
Snackbar.Add($"Error rotating to angle: {ex.Message}", Severity.Error);
}
finally
{
isLoading = false;
StateHasChanged();
}
}
private async Task RotateOffset()
{
if (!IsHubReady || isLoading || rotationStatus?.IsReady != true)
return;
try
{
isLoading = true;
var offsetText = angleOffset >= 0 ? $"+{angleOffset}°" : $"{angleOffset}°";
Snackbar.Add($"Rotating offset {offsetText}...", Severity.Info);
await HubClient.RotateOffsetAsync(angleOffset);
Snackbar.Add($"Rotate offset {offsetText} command sent successfully", Severity.Success);
await Task.Delay(500);
await RefreshStatus();
}
catch (Exception ex)
{
Snackbar.Add($"Error rotating offset: {ex.Message}", Severity.Error);
}
finally
{
isLoading = false;
StateHasChanged();
}
}
private async Task RotateOffsetQuick(double offset)
{
angleOffset = offset;
await RotateOffset();
}
}