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

260 lines
9.5 KiB
Plaintext

@using RobotNet10.FleetManager.Shared.DTOs.RobotModel
@using RobotNet10.FleetManager.Shared.Enums
@using RobotNet10.FleetManager.Client.Services
@using RobotNet10.MapEditor.Services.API
@using RobotNet10.MapEditor.Shared.DTOs.VehicleType
@inject ISnackbar Snackbar
@inject MapManagerApiService MapApiService
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.Edit" Color="Color.Primary" Class="mr-2" />
Edit Robot Model
</MudText>
</TitleContent>
<DialogContent>
<MudStack Spacing="3">
<MudTextField @bind-Value="request.ModelName"
Label="Model Name"
Variant="Variant.Outlined"
ErrorText="@GetValidationError("ModelName")" />
<MudNumericField T="double?" @bind-Value="request.Length"
Label="Length (m)"
Variant="Variant.Outlined"
Min="0.01"
Max="1000"
Step="0.01"
ErrorText="@GetValidationError("Length")" />
<MudNumericField T="double?" @bind-Value="request.Width"
Label="Width (m)"
Variant="Variant.Outlined"
Min="0.01"
Max="1000"
Step="0.01"
ErrorText="@GetValidationError("Width")" />
<MudNumericField T="double?" @bind-Value="request.NavigationPointX"
Label="Navigation Point X (m)"
Variant="Variant.Outlined"
Step="0.01"
ErrorText="@GetValidationError("NavigationPointX")" />
<MudNumericField T="double?" @bind-Value="request.NavigationPointY"
Label="Navigation Point Y (m)"
Variant="Variant.Outlined"
Step="0.01"
ErrorText="@GetValidationError("NavigationPointY")" />
<MudSelect @bind-Value="request.NavigationType"
Label="Navigation Type"
Variant="Variant.Outlined"
T="NavigationType?"
ErrorText="@GetValidationError("NavigationType")" ReadOnly>
@foreach (NavigationType navType in Enum.GetValues<NavigationType>())
{
<MudSelectItem Value="@((NavigationType?)navType)">@navType.ToString()</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="request.VehicleTypeId"
Label="Vehicle Type (Optional)"
Variant="Variant.Outlined"
T="Guid?"
Clearable="true"
Disabled="@isLoadingVehicleTypes"
ErrorText="@GetValidationError("VehicleTypeId")">
@if (isLoadingVehicleTypes)
{
<MudSelectItem Value="@((Guid?)null)" Disabled="true">Loading vehicle types...</MudSelectItem>
}
else if (vehicleTypes != null && vehicleTypes.Any())
{
<MudSelectItem Value="@((Guid?)null)">None</MudSelectItem>
@foreach (var vehicleType in vehicleTypes)
{
<MudSelectItem Value="@((Guid?)vehicleType.Id)">@($"{vehicleType.VehicleTypeId} - {vehicleType.VehicleTypeName}")</MudSelectItem>
}
}
else
{
<MudSelectItem Value="@((Guid?)null)" Disabled="true">No vehicle types available</MudSelectItem>
}
</MudSelect>
<MudDivider />
<MudText Typo="Typo.subtitle2">Image Upload (Optional - Leave empty to keep current image)</MudText>
<MudFileUpload T="IBrowserFile"
@bind-Files="selectedFile"
Accept=".png"
MaximumFileCount="1">
<CustomContent>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
OnClick="@context.OpenFilePickerAsync">
Upload New Image (PNG)
</MudButton>
</CustomContent>
</MudFileUpload>
@if (selectedFile != null)
{
<MudChip T="string" Color="Color.Success" Icon="@Icons.Material.Filled.AttachFile">
@selectedFile.Name (@FormatFileSize(selectedFile.Size))
</MudChip>
}
</MudStack>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Color="Color.Primary"
Variant="Variant.Filled"
OnClick="Submit"
Disabled="@isUpdating">
@if (isUpdating)
{
<MudProgressCircular Class="mr-2" Size="Size.Small" Indeterminate="true" />
<span>Updating...</span>
}
else
{
<span>Update</span>
}
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] private IMudDialogInstance? MudDialog { get; set; }
[Parameter] public RobotModelApiService ApiService { get; set; } = null!;
[Parameter] public RobotModelDto RobotModel { get; set; } = null!;
private UpdateRobotModelRequest request = new();
private IBrowserFile? selectedFile;
private Dictionary<string, string> validationErrors = new();
private bool isUpdating = false;
private List<VehicleTypeDto>? vehicleTypes;
private bool isLoadingVehicleTypes = false;
protected override async Task OnInitializedAsync()
{
// Pre-fill with existing data
request.ModelName = RobotModel.ModelName;
request.Length = RobotModel.Length;
request.Width = RobotModel.Width;
request.NavigationPointX = RobotModel.NavigationPointX;
request.NavigationPointY = RobotModel.NavigationPointY;
request.NavigationType = RobotModel.NavigationType; // This is nullable, but we set it to the actual value
request.VehicleTypeId = RobotModel.VehicleTypeId;
await LoadVehicleTypesAsync();
}
private async Task LoadVehicleTypesAsync()
{
isLoadingVehicleTypes = true;
StateHasChanged();
try
{
vehicleTypes = await MapApiService.GetVehicleTypesAsync(isActive: true);
}
catch (Exception ex)
{
Snackbar.Add($"Error loading vehicle types: {ex.Message}", Severity.Warning);
vehicleTypes = new List<VehicleTypeDto>();
}
finally
{
isLoadingVehicleTypes = false;
StateHasChanged();
}
}
private bool Validate()
{
validationErrors.Clear();
if (!string.IsNullOrWhiteSpace(request.ModelName) && request.ModelName.Length > 256)
{
validationErrors["ModelName"] = "Model Name must be 256 characters or less";
}
if (request.Length.HasValue && request.Length.Value <= 0)
{
validationErrors["Length"] = "Length must be greater than 0";
}
if (request.Width.HasValue && request.Width.Value <= 0)
{
validationErrors["Width"] = "Width must be greater than 0";
}
return validationErrors.Count == 0;
}
private string? GetValidationError(string fieldName)
{
return validationErrors.TryGetValue(fieldName, out var error) ? error : null;
}
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]}";
}
private void Cancel()
{
MudDialog?.Cancel();
}
private async Task Submit()
{
if (!Validate())
{
Snackbar.Add("Please fix validation errors", Severity.Warning);
StateHasChanged();
return;
}
isUpdating = true;
StateHasChanged();
try
{
// Update robot model
var updated = await ApiService.UpdateAsync(RobotModel.Id, request);
// Upload new image if provided
if (selectedFile != null)
{
using var stream = selectedFile.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024); // 10MB
await ApiService.UploadImageAsync(updated.Id, stream, selectedFile.Name);
}
Snackbar.Add($"Robot model '{updated.ModelName}' updated successfully", Severity.Success);
MudDialog?.Close(DialogResult.Ok(updated));
}
catch (Exception ex)
{
Snackbar.Add($"Error updating robot model: {ex.Message}", Severity.Error);
}
finally
{
isUpdating = false;
StateHasChanged();
}
}
}