From 84f4990ff4c52a7d64dbbc706502ee37efd78c0d Mon Sep 17 00:00:00 2001 From: Loretta Date: Sun, 22 Mar 2026 20:01:49 +0100 Subject: [PATCH] Add MgCardView component & refactor MeasuringOut to tabs Introduced a reusable, responsive MgCardView component for displaying data as cards with optional filtering and paging. Refactored the MeasuringOut page to use a tabbed interface: daily tasks are now shown as filterable cards, and measuring details are separated into a dedicated tab. Improved UI clarity, code organization, and maintainability. --- .../Pages/MeasuringIn.razor | 2 +- .../Pages/MeasuringOut.razor | 460 ++++++++++-------- .../Pages/MeasuringOut.razor.cs | 119 +++-- FruitBankHybrid.Shared/wwwroot/app.css | 11 +- 4 files changed, 343 insertions(+), 249 deletions(-) diff --git a/FruitBankHybrid.Shared/Pages/MeasuringIn.razor b/FruitBankHybrid.Shared/Pages/MeasuringIn.razor index 08dfd587..63124bf9 100644 --- a/FruitBankHybrid.Shared/Pages/MeasuringIn.razor +++ b/FruitBankHybrid.Shared/Pages/MeasuringIn.razor @@ -10,7 +10,7 @@

Áru bevételezés

-
+
Áru kiadás -
- +
- - + -
-
-
- - - @{ - var cssClass = GetMeasuringDateCssClassNames(ctxOrderDate); - if (!cssClass.IsNullOrWhiteSpace()) - { - @ctxOrderDate.Day.ToString() - } - else - { - @ctxOrderDate.Day.ToString() - } - } - - -
-
- -
-
-
+ + + @{ + var cssClass = GetMeasuringDateCssClassNames(ctxOrderDate); + if (!cssClass.IsNullOrWhiteSpace()) + { + @ctxOrderDate.Day.ToString() + } + else + { + @ctxOrderDate.Day.ToString() + } + } + +
- - - - - @ctxOrder.DisplayText - - - - - + + - - @if (SelectedOrder == null) - { - - } - else - { - if (SelectedOrder is { MeasurementOwnerId: 0, IsComplete: false } && HasMeasuringAccess) - { - - - - } - else - { - - - - } - } - - @* *@ - @if (SelectedOrder != null && LoggedInModel.IsRevisor) - { - var isCompleteOrder = SelectedOrder.IsComplete; - - - - - }
- @if (SelectedOrder == null || LoadingPanelVisible) - { - } - else if (!HasMeasuringAccess) - { -
-

Mások végzik a mérést!

-
- } - else - { - string? orderNote; - if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x => x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace()) - { -
- Megjegyzés: @(orderNote) + + +
+ + + + + +
+
#@context.CustomOrderNumber
+ @GetOrderStatusText(context.MeasuringStatus) +
+
+ @context.DateOfReceiptOrCreated.ToString("H:mm") — @context.Customer.Company +
+ @foreach (var item in context.OrderItemDtos) + { +
+ @item.ProductName — @item.TrayQuantity/@item.Quantity rekesz +
+ } +
+
- } +
+ +
+ + + + + @ctxOrder.DisplayText + + + + + + -
-

- Rendelés azonosító: #@(SelectedOrder?.CustomOrderNumber) -

- - - - - @* *@ - - - @{ - if (context.Level == 0) + @if (SelectedOrder == null) + { + + + + } + else + { + if (SelectedOrder is { MeasurementOwnerId: 0, IsComplete: false } && HasMeasuringAccess) { - var cssClass = "text-danger"; - - var selectedOrderItemDto = (OrderItemDto)(context.DataItem); - var trayQuantity = selectedOrderItemDto.TrayQuantity; //selectedOrderItemDto.OrderItemPallets.Where(x => x.IsMeasured).Sum(x => x.TrayQuantity); - - var isValid = selectedOrderItemDto.IsValidMeasuringValues(); - var isValidAndMeasured = isValid && selectedOrderItemDto.IsMeasuredAndValid(); // && selectedOrderItemDto.; - - if (isValid && !selectedOrderItemDto.AverageWeightIsValid) cssClass = "text-warning"; - else if (isValidAndMeasured) cssClass = "text-success"; - else if (isValid) cssClass = string.Empty; - - var displayText = $"{selectedOrderItemDto.ProductName} - [{trayQuantity}/{selectedOrderItemDto.Quantity} rekesz, {(selectedOrderItemDto.IsMeasurable ? "net.súly: " + selectedOrderItemDto.NetWeight + "kg." : "nem mérendő!")}]"; - if (selectedOrderItemDto.MeasuringStatus == MeasuringStatus.Audited) displayText = $"[{selectedOrderItemDto.MeasuringStatus}] " + displayText; - -
@(displayText)
+ + + + } + else + { + + + } } -
- - @{ - if (context.Level == 0) - { - var selectedOrderItem = (OrderItemDto)(context.DataItem); - - - @for (var index = 0; index < (selectedOrderItem?.OrderItemPallets?.Count ?? 0); index++) + @if (SelectedOrder != null && LoggedInModel.IsRevisor) + { + var isCompleteOrder = SelectedOrder.IsComplete; + + + + + } + + + @if (SelectedOrder == null || LoadingPanelVisible) + { + } + else if (!HasMeasuringAccess) + { + + } + else + { + string? orderNote; + if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x => x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace()) + { + + } + +
+

+ Rendelés azonosító: #@(SelectedOrder?.CustomOrderNumber) +

+ + + + + + + @{ + if (context.Level == 0) { - var localI = index + 1; - var currentOrderItemPallet = selectedOrderItem!.OrderItemPallets![index]; + var cssClass = "text-danger"; - - + var selectedOrderItemDto = (OrderItemDto)(context.DataItem); + var trayQuantity = selectedOrderItemDto.TrayQuantity; //selectedOrderItemDto.OrderItemPallets.Where(x => x.IsMeasured).Sum(x => x.TrayQuantity); + + var isValid = selectedOrderItemDto.IsValidMeasuringValues(); + var isValidAndMeasured = isValid && selectedOrderItemDto.IsMeasuredAndValid(); // && selectedOrderItemDto.; + + if (isValid && !selectedOrderItemDto.AverageWeightIsValid) cssClass = "text-warning"; + else if (isValidAndMeasured) cssClass = "text-success"; + else if (isValid) cssClass = string.Empty; + + var displayText = $"{selectedOrderItemDto.ProductName} - [{trayQuantity}/{selectedOrderItemDto.Quantity} rekesz, {(selectedOrderItemDto.IsMeasurable ? "net.súly: " + selectedOrderItemDto.NetWeight + "kg." : "nem mérendő!")}]"; + if (selectedOrderItemDto.MeasuringStatus == MeasuringStatus.Audited) displayText = $"[{selectedOrderItemDto.MeasuringStatus}] " + displayText; + +
@(displayText)
} - - - - - - - - - - - - - - TOTAL: - - - - Rekesz: @(selectedOrderItem.TrayQuantity) db - Br: @(selectedOrderItem.GrossWeight) kg - Net: @(selectedOrderItem.NetWeight) kg - - - - - @if (!_errorText.IsNullOrWhiteSpace()) - { - - HIBA! @_errorText - - //_errorText = string.Empty; } - -
- } - } - -
-
- } + + + @{ + if (context.Level == 0) + { + var selectedOrderItem = (OrderItemDto)(context.DataItem); + + + + @for (var index = 0; index < (selectedOrderItem?.OrderItemPallets?.Count ?? 0); index++) + { + var localI = index + 1; + var currentOrderItemPallet = selectedOrderItem!.OrderItemPallets![index]; + + + + } + + + + + + + + + + + + + + TOTAL: + + + + Rekesz: @(selectedOrderItem.TrayQuantity) db + Br: @(selectedOrderItem.GrossWeight) kg + Net: @(selectedOrderItem.NetWeight) kg + + + + + @if (!_errorText.IsNullOrWhiteSpace()) + { + + + + } + +
+ } + } +
+
+
+ } +
+
+
diff --git a/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs b/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs index 85858aa0..23d5f0dd 100644 --- a/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs +++ b/FruitBankHybrid.Shared/Pages/MeasuringOut.razor.cs @@ -4,6 +4,7 @@ using AyCode.Services.SignalRs; using DevExpress.Blazor; using FruitBank.Common.Dtos; using FruitBank.Common.Entities; +using FruitBank.Common.Enums; using FruitBank.Common.Models; using FruitBank.Common.SignalRs; using FruitBankHybrid.Shared.Extensions; @@ -30,8 +31,16 @@ namespace FruitBankHybrid.Shared.Pages private LoggerClient _logger = null!; private string _errorText; + private enum MeasuringTab + { + DailyTasks = 0, + Measuring = 1 + } + private bool _enablePalletItems = true; private int _lastDaysCount = 1; + private MeasuringTab _activeTab = MeasuringTab.DailyTasks; + private IEnumerable _statusFilter = [MeasuringStatus.NotStarted, MeasuringStatus.Started, MeasuringStatus.Finnished]; public bool HasMeasuringAccess; public bool LoadingPanelVisible { get; set; } = true; public bool IsAllOrderItemPalletAudited => SelectedOrder?.IsAllOrderItemAudited ?? false; @@ -42,6 +51,12 @@ namespace FruitBankHybrid.Shared.Pages private List _measuringDates = null!; + private IReadOnlyList FilteredOrders => SelectedDayOrders is null + ? [] + : _statusFilter.Any() + ? SelectedDayOrders.Where(o => _statusFilter.Contains(o.MeasuringStatus)).ToList() + : SelectedDayOrders; + protected override async Task OnInitializedAsync() { LoadingPanelVisible = true; @@ -187,7 +202,7 @@ namespace FruitBankHybrid.Shared.Pages SelectedOrder ??= SelectedDayOrders.FirstOrDefault(); } - LoadingPanelVisible = SelectedOrder != null; //Lefut a change és ott lesz false! - J. + LoadingPanelVisible = false; } private async Task OnMeasuringDateChanged(DateTime selectedDateTime) => await RefreshOrdersFromDb(selectedDateTime, _lastDaysCount); @@ -206,42 +221,11 @@ namespace FruitBankHybrid.Shared.Pages private async Task OnSelectedOrderChanged(SelectedDataItemChangedEventArgs eventArgs) { - //var orderDtosFromDb = await FruitBankSignalRClient.GetPendingOrderDtos(); - //if (orderDtosFromDb != null) RefreshOrderGenericAttributes(orderDtosFromDb, SelectedDayOrders); - //else MessageBox.ShowMessageBox("Hiba", "Az adatok letöltése sikertelen!", MessageBoxRenderStyle.Danger); - var orderDto = eventArgs.DataItem; if (orderDto != null && !LoadingPanelVisible) - { - //LoadingPanelVisible = true; - var orderFromDb = await FruitBankSignalRClient.GetOrderDtoById(orderDto.Id); + await RefreshOrderStatusFromDbAsync(orderDto); - if (orderFromDb != null) - { - orderDto.OrderStatus = orderFromDb.OrderStatus; - orderDto.GenericAttributes.UpdateBaseEntityCollection(orderFromDb.GenericAttributes, false); - - //if (LoggedInModel.IsRevisor) - //{ - // orderDto.OrderItemDtos.UpdateCollection(orderFromDb.OrderItemDtos, false); - - // var orderItemPalletsByOrderId = orderFromDb.OrderItemDtos.Where(o => o.OrderItemPallets.Count > 0).ToDictionary(k => k.Id, v => v.OrderItemPallets); - // foreach (var orderItemDto in orderDto.OrderItemDtos) - // { - // if (orderItemPalletsByOrderId.TryGetValue(orderDto.Id, out var orderItemPallets)) - // orderItemDto.OrderItemPallets.UpdateCollection(orderItemPallets, false); - // } - //} - } - } - - LoadingPanelVisible = false; - HasMeasuringAccess = orderDto?.HasMeasuringAccess(LoggedInModel.CustomerDto?.Id, LoggedInModel.IsRevisor) ?? false; - - StateHasChanged(); - - if (!HasMeasuringAccess && orderDto != null) - await DialogService.ShowMessageBoxAsync("Információ", "A mérés már folyamatban, válasszon másik rendelést!", MessageBoxRenderStyle.Info); + await ApplyMeasuringAccessAsync(orderDto); } private Task OnOrderItemPalletValueChanged(OrderItemPallet orderItemPallet, OrderItemDto selectedOrderItemDto) @@ -383,6 +367,73 @@ namespace FruitBankHybrid.Shared.Pages } } + /// + /// Navigates from a card click (Napi feladatok tab) to the Mérés tab with the selected order. + /// Loads the full order from DB and switches the active tab. + /// + private async Task NavigateToMeasuringTab(OrderDto order) + { + LoadingPanelVisible = true; + SelectedOrder = order; + + await RefreshOrderStatusFromDbAsync(order); + + _activeTab = MeasuringTab.Measuring; + + await ApplyMeasuringAccessAsync(order); + } + + /// + /// Fetches the latest order data from DB and updates status and generic attributes. + /// + private async Task RefreshOrderStatusFromDbAsync(OrderDto order) + { + var orderFromDb = await FruitBankSignalRClient.GetOrderDtoById(order.Id); + if (orderFromDb != null) + { + order.OrderStatus = orderFromDb.OrderStatus; + order.GenericAttributes.UpdateBaseEntityCollection(orderFromDb.GenericAttributes, false); + } + } + + /// + /// Sets measuring access, hides loading panel, refreshes UI, and shows info dialog if access is denied. + /// + private async Task ApplyMeasuringAccessAsync(OrderDto? order) + { + HasMeasuringAccess = order?.HasMeasuringAccess(LoggedInModel.CustomerDto?.Id, LoggedInModel.IsRevisor) ?? false; + LoadingPanelVisible = false; + + StateHasChanged(); + + if (!HasMeasuringAccess && order != null) + await DialogService.ShowMessageBoxAsync("Információ", "A mérés már folyamatban, válasszon másik rendelést!", MessageBoxRenderStyle.Info); + } + + private static string GetOrderStatusCssClass(MeasuringStatus status) => status switch + { + MeasuringStatus.Audited => "text-success", + MeasuringStatus.Finnished => "text-primary", + MeasuringStatus.Started => "text-warning", + _ => "text-muted" + }; + + private static string GetOrderStatusBadgeCssClass(MeasuringStatus status) => status switch + { + MeasuringStatus.Audited => "bg-success", + MeasuringStatus.Finnished => "bg-primary", + MeasuringStatus.Started => "bg-warning text-dark", + _ => "bg-secondary" + }; + + private static string GetOrderStatusText(MeasuringStatus status) => status switch + { + MeasuringStatus.Audited => "Lezárva", + MeasuringStatus.Finnished => "Kész", + MeasuringStatus.Started => "Folyamatban", + _ => "Nem kezdett" + }; + public void Dispose() { FruitBankSignalRClient.OnMessageReceived -= SignalRClientOnMessageReceived; diff --git a/FruitBankHybrid.Shared/wwwroot/app.css b/FruitBankHybrid.Shared/wwwroot/app.css index 7f7ea73c..71e41aa0 100644 --- a/FruitBankHybrid.Shared/wwwroot/app.css +++ b/FruitBankHybrid.Shared/wwwroot/app.css @@ -79,12 +79,19 @@ h1:focus { .measuring-form-layout { margin-top: 15px; - margin-bottom: 25px; + margin-bottom: 10px; padding: 8px; - background-color: lightgrey; + background-color: #e9eff5; + border: 1px solid #d5dde6; border-radius: 8px; } +.measuring-tabs { + border: 1px solid #d5dde6; + border-radius: 8px; + padding: 0; +} + .dd-body-class, .dd-body-class .dxbl-list-box-render-container { max-height: 600px !important;