This commit is contained in:
Adam 2025-11-18 11:24:38 +01:00
commit c5e019f051
12 changed files with 125 additions and 70 deletions

View File

@ -3,11 +3,8 @@ using LinqToDB.Mapping;
using Mango.Nop.Core.Dtos; using Mango.Nop.Core.Dtos;
using Mango.Nop.Core.Extensions; using Mango.Nop.Core.Extensions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Nop.Core;
//using Nop.Core.Domain.Catalog; //using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common; using Nop.Core.Domain.Common;
using Nop.Core.Domain.Orders;
using System.Globalization;
using System.Linq.Expressions; using System.Linq.Expressions;
namespace FruitBank.Common.Dtos; namespace FruitBank.Common.Dtos;

View File

@ -1,12 +1,11 @@
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
namespace FruitBank.Common namespace FruitBank.Common
{ {
public interface IFastObservableCollection public interface IMgFastObservableCollection
{ {
public void AddRange(IEnumerable other); public void AddRange(IEnumerable other);
public void Replace(IEnumerable other); public void Replace(IEnumerable other);
@ -14,20 +13,20 @@ namespace FruitBank.Common
public void Synchronize(NotifyCollectionChangedEventArgs args); public void Synchronize(NotifyCollectionChangedEventArgs args);
} }
public interface IFastObservableCollection<T>: IFastObservableCollection public interface IMgFastObservableCollection<T> : IMgFastObservableCollection
{ {
public void Replace(IEnumerable<T> other); public void Replace(IEnumerable<T> other);
public void Sort(IComparer<T> comparer); public void Sort(IComparer<T> comparer);
public void SortAndReplace(IEnumerable<T> other, IComparer<T> comparer); public void SortAndReplace(IEnumerable<T> other, IComparer<T> comparer);
} }
public class FastObservableCollection<T> : ObservableCollection<T>, IFastObservableCollection<T> public class MgObservableCollection<T> : ObservableCollection<T>, IMgFastObservableCollection<T>
{ {
private bool suppressChangedEvent = false; private bool _suppressChangedEvent;
public void Replace(IEnumerable<T> other) public void Replace(IEnumerable<T> other)
{ {
suppressChangedEvent = true; _suppressChangedEvent = true;
Clear(); Clear();
AddRange(other); AddRange(other);
@ -35,45 +34,45 @@ namespace FruitBank.Common
public void Replace(IEnumerable other) public void Replace(IEnumerable other)
{ {
suppressChangedEvent = true; _suppressChangedEvent = true;
Clear(); Clear();
foreach (T item in other) Add(item); foreach (T item in other) Add(item);
suppressChangedEvent = false; _suppressChangedEvent = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new(nameof(Count))); OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
} }
public void AddRange(IEnumerable other) public void AddRange(IEnumerable other)
{ {
suppressChangedEvent = true; _suppressChangedEvent = true;
foreach (object item in other) foreach (var item in other)
{ {
if (item is T tItem) Add(tItem); if (item is T tItem) Add(tItem);
} }
suppressChangedEvent = false; _suppressChangedEvent = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new(nameof(Count))); OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
} }
public void RemoveRange(IEnumerable other) public void RemoveRange(IEnumerable other)
{ {
suppressChangedEvent = true; _suppressChangedEvent = true;
foreach (object item in other) foreach (var item in other)
{ {
if (item is T tItem) Remove(tItem); if (item is T tItem) Remove(tItem);
} }
suppressChangedEvent = false; _suppressChangedEvent = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new(nameof(Count))); OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
} }
public void SortAndReplace(IEnumerable<T> other, IComparer<T> comparer) public void SortAndReplace(IEnumerable<T> other, IComparer<T> comparer)
@ -94,23 +93,28 @@ namespace FruitBank.Common
public void Synchronize(NotifyCollectionChangedEventArgs args) public void Synchronize(NotifyCollectionChangedEventArgs args)
{ {
if (args.Action == NotifyCollectionChangedAction.Add && args.NewItems != null) switch (args.Action)
{ {
AddRange(args.NewItems); case NotifyCollectionChangedAction.Add when args.NewItems != null:
} AddRange(args.NewItems);
else if (args.Action == NotifyCollectionChangedAction.Remove && args.OldItems != null) break;
{ case NotifyCollectionChangedAction.Remove when args.OldItems != null:
RemoveRange(args.OldItems); RemoveRange(args.OldItems);
} break;
else if (args.Action == NotifyCollectionChangedAction.Reset) case NotifyCollectionChangedAction.Reset:
{ Clear();
Clear(); break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move:
break;
default:
throw new ArgumentOutOfRangeException();
} }
} }
protected override void OnPropertyChanged(PropertyChangedEventArgs e) protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{ {
if (suppressChangedEvent) if (_suppressChangedEvent)
return; return;
base.OnPropertyChanged(e); base.OnPropertyChanged(e);
@ -118,10 +122,31 @@ namespace FruitBank.Common
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{ {
if (suppressChangedEvent) if (_suppressChangedEvent)
return; return;
base.OnCollectionChanged(e); base.OnCollectionChanged(e);
} }
}
//protected override void ClearItems()
//{
// base.ClearItems();
//}
//protected override void InsertItem(int index, T item)
//{
// base.InsertItem(index, item);
//}
//protected override void MoveItem(int oldIndex, int newIndex)
//{
// base.MoveItem(oldIndex, newIndex);
//}
//public override event NotifyCollectionChangedEventHandler? CollectionChanged
//{
// add => base.CollectionChanged += value;
// remove => base.CollectionChanged -= value;
//}
}
} }

View File

@ -48,5 +48,6 @@ public class LoggedInModel
{ {
CustomerDto = null; CustomerDto = null;
CustomerRoles.Clear(); CustomerRoles.Clear();
//MeasuringUsers.Clear();
} }
} }

View File

@ -1,5 +1,12 @@
namespace FruitBankHybrid.Shared.Components; using DevExpress.Blazor;
namespace FruitBankHybrid.Shared.Components;
public class GridProductDto : MgGridBase public class GridProductDto : MgGridBase
{ {
protected override void CustomizeElementHideDetailButton(GridCustomizeElementEventArgs e)
{
//Felülírjuk, h ne adja hozzá a "hideDetailButton" css class-t!
return;
}
} }

View File

@ -1,4 +1,5 @@
@using AyCode.Core.Helpers @using System.Threading
@using AyCode.Core.Helpers
@using AyCode.Utils.Extensions @using AyCode.Utils.Extensions
@using DevExpress.Internal.About @using DevExpress.Internal.About
@using FruitBank.Common.Dtos @using FruitBank.Common.Dtos
@ -27,19 +28,19 @@
<DxGridCommandColumn Visible="!IsMasterGrid" Width="120"></DxGridCommandColumn> <DxGridCommandColumn Visible="!IsMasterGrid" Width="120"></DxGridCommandColumn>
</Columns> </Columns>
<DetailRowTemplate> <DetailRowTemplate>
@if (IsMasterGrid && LoggedInModel.IsDeveloper) @if (IsMasterGrid)
{ {
var productId = ((ProductDto)context.DataItem).Id; var productId = ((ProductDto)context.DataItem).Id;
<DxTabs ActiveTabIndexChanged="(i) => OnActiveTabChanged(i, productId)"> <DxTabs ActiveTabIndexChanged="(i) => OnActiveTabChanged(i, productId)">
<DxTabPage Text="Rendelések melyben megtalálható"> <DxTabPage Text="Rendelések melyben megtalálható" Visible="@LoggedInModel.IsDeveloper">
@{ @{
//GetOrderDtosFromDbAsync(productId).Forget(); //GetOrderDtosFromDbAsync(productId).Forget();
//var orderDtos = _orderDtos?.Where(o => o.OrderItemDtos.Any(oi => oi.ProductId == productId)).ToList() ?? []; //var orderDtos = _orderDtos?.Where(o => o.OrderItemDtos.Any(oi => oi.ProductId == productId)).ToList() ?? [];
<GridDetailOrderDto OrderDtos="_currentOrderDtos" IsMasterGrid="false"></GridDetailOrderDto> <GridDetailOrderDto OrderDtos="_currentOrderDtos" IsMasterGrid="false"></GridDetailOrderDto>
} }
</DxTabPage> </DxTabPage>
<DxTabPage Text="Rendelés tételek"> <DxTabPage Text="Rendelés tételek" Visible="@LoggedInModel.IsDeveloper">
@{ @{
//GetOrderItemDtosFromDbAsync(productId).Forget(); //GetOrderItemDtosFromDbAsync(productId).Forget();
//var orderItemDtos = _orderItemDtos?.Where(oi => oi.ProductId == productId).ToList() ?? []; //var orderItemDtos = _orderItemDtos?.Where(oi => oi.ProductId == productId).ToList() ?? [];
@ -77,12 +78,16 @@
private List<OrderDto>? _currentOrderDtos; private List<OrderDto>? _currentOrderDtos;
private List<OrderItemDto>? _currentOrderItemDtos; private List<OrderItemDto>? _currentOrderItemDtos;
private readonly SemaphoreSlim _lockOrderDtosByProductId = new(1);
private readonly SemaphoreSlim _lockOrderItemDtosByProductId = new(1);
private readonly Dictionary<int, List<OrderDto>> _orderDtosByProductId = new(); private readonly Dictionary<int, List<OrderDto>> _orderDtosByProductId = new();
private readonly Dictionary<int, List<OrderItemDto>> _orderItemDtosByProductId = new(); private readonly Dictionary<int, List<OrderItemDto>> _orderItemDtosByProductId = new();
public GridProductDto Grid { get; set; } public GridProductDto Grid { get; set; }
[Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public bool IsMasterGrid { get; set; } = false;
[Parameter] public IEnumerable<ProductDto>? ProductDtos { get; set; } [Parameter] public IEnumerable<ProductDto>? ProductDtos { get; set; }
//[Parameter] public List<OrderDto>? OrderDtos { get; set; } //[Parameter] public List<OrderDto>? OrderDtos { get; set; }
//[Parameter] public List<OrderItemDto>? OrderItemDtos { get; set; } //[Parameter] public List<OrderItemDto>? OrderItemDtos { get; set; }
@ -125,29 +130,37 @@
private async Task<List<OrderDto>> GetOrderDtosFromDbAsync(int productId) private async Task<List<OrderDto>> GetOrderDtosFromDbAsync(int productId)
{ {
if (_orderDtosByProductId.TryGetValue(productId, out var orderDtos)) return orderDtos; using (await _lockOrderDtosByProductId.UseWaitAsync())
{
if (_orderDtosByProductId.TryGetValue(productId, out var orderDtos)) return orderDtos;
orderDtos = await FruitBankSignalRClient.GetAllOrderDtoByProductId(productId) ?? []; orderDtos = await FruitBankSignalRClient.GetAllOrderDtoByProductId(productId) ?? [];
_orderDtosByProductId[productId] = orderDtos; _orderDtosByProductId[productId] = orderDtos;
return _currentOrderDtos = orderDtos; return _currentOrderDtos = orderDtos;
}
} }
private async Task<List<OrderItemDto>> GetOrderItemDtosFromDbAsync(int productId) private async Task<List<OrderItemDto>> GetOrderItemDtosFromDbAsync(int productId)
{ {
if (_orderItemDtosByProductId.TryGetValue(productId, out var orderItemDtos)) return orderItemDtos; using (await _lockOrderItemDtosByProductId.UseWaitAsync())
{
if (_orderItemDtosByProductId.TryGetValue(productId, out var orderItemDtos)) return orderItemDtos;
orderItemDtos = await FruitBankSignalRClient.GetAllOrderItemDtoByProductId(productId) ?? []; orderItemDtos = await FruitBankSignalRClient.GetAllOrderItemDtoByProductId(productId) ?? [];
_orderItemDtosByProductId[productId] = orderItemDtos; _orderItemDtosByProductId[productId] = orderItemDtos;
return _currentOrderItemDtos = orderItemDtos; return _currentOrderItemDtos = orderItemDtos;
}
} }
protected async Task OnFocusedRowChanged(GridFocusedRowChangedEventArgs e) protected async Task OnFocusedRowChanged(GridFocusedRowChangedEventArgs e)
{ {
if (!LoggedInModel.IsDeveloper) return;
var productDto = (ProductDto)e.DataItem; var productDto = (ProductDto)e.DataItem;
//if (e.Grid.IsDetailRowExpanded(e.VisibleIndex)) if (e.Grid.IsDetailRowExpanded(e.VisibleIndex))
{ {
_currentOrderDtos = null; _currentOrderDtos = null;
_currentOrderDtos = productDto != null ? await GetOrderDtosFromDbAsync(productDto.Id) : []; _currentOrderDtos = productDto != null ? await GetOrderDtosFromDbAsync(productDto.Id) : [];

View File

@ -1,19 +1,15 @@
using AyCode.Core.Interfaces; using DevExpress.Blazor;
using DevExpress.Blazor;
using FruitBank.Common.Dtos; using FruitBank.Common.Dtos;
using FruitBank.Common.Entities;
using FruitBank.Common.SignalRs; using FruitBank.Common.SignalRs;
using FruitBankHybrid.Shared.Pages;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace FruitBankHybrid.Shared.Components.Grids.ShippingItems; namespace FruitBankHybrid.Shared.Components.Grids.Products;
public class GridStockQuantityHistoryDto : FruitBankListGridBase<StockQuantityHistoryDto>, IGrid public class GridStockQuantityHistoryDto : FruitBankListGridBase<StockQuantityHistoryDto>, IGrid
{ {
public GridStockQuantityHistoryDto() : base() public GridStockQuantityHistoryDto() : base()
{ {
if (IsMasterGrid) GetAllMessageTag = SignalRTags.GetStockQuantityHistoryDtos; GetAllMessageTag = IsMasterGrid ? SignalRTags.GetStockQuantityHistoryDtos : SignalRTags.GetStockQuantityHistoryDtosByProductId;
else GetAllMessageTag = SignalRTags.GetStockQuantityHistoryDtosByProductId;
//AddMessageTag = SignalRTags.AddShippingItem; //AddMessageTag = SignalRTags.AddShippingItem;
//UpdateMessageTag = SignalRTags.UpdateShippingItem; //UpdateMessageTag = SignalRTags.UpdateShippingItem;

View File

@ -1,9 +1,6 @@
@using AyCode.Core.Loggers; @using AyCode.Core.Loggers;
@using AyCode.Core.Extensions
@using AyCode.Core.Helpers
@using AyCode.Utils.Extensions @using AyCode.Utils.Extensions
@using FruitBank.Common.Dtos @using FruitBank.Common.Dtos
@using FruitBank.Common.Entities
@using FruitBankHybrid.Shared.Components.Grids.ShippingItems @using FruitBankHybrid.Shared.Components.Grids.ShippingItems
@using FruitBankHybrid.Shared.Components.Toolbars @using FruitBankHybrid.Shared.Components.Toolbars
@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Databases
@ -57,17 +54,15 @@
[Inject] public required DatabaseClient Database { get; set; } [Inject] public required DatabaseClient Database { get; set; }
[Parameter] public object[]? ContextIds { get; set; } [Parameter] public object[]? ContextIds { get; set; }
[Parameter] public bool IsMasterGrid { get; set; } = false; [Parameter] public bool IsMasterGrid { get; set; }
[Parameter] public IEnumerable<ProductDto>? ProductDtos { get; set; } [Parameter] public IEnumerable<ProductDto>? ProductDtos { get; set; }
[Parameter] public List<StockQuantityHistoryDto>? StockQuantityHistoryDtos { get; set; } [Parameter] public List<StockQuantityHistoryDto>? StockQuantityHistoryDtos { get; set; }
string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty; string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty;
const string ExportFileName = "ExportResult";
public GridStockQuantityHistoryDto Grid { get; set; } public GridStockQuantityHistoryDto Grid { get; set; }
private LoggerClient<GridStockQuantityHistoryDtoTemplate> _logger; private LoggerClient<GridStockQuantityHistoryDtoTemplate> _logger = null!;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {

View File

@ -41,6 +41,14 @@ public class MgGridBase : DxGrid
// Layouts = JsonSerializer.Deserialize<ObservableCollection<UserLayout>>(json); // Layouts = JsonSerializer.Deserialize<ObservableCollection<UserLayout>>(json);
} }
protected virtual void CustomizeElementHideDetailButton(GridCustomizeElementEventArgs e)
{
if (e.ElementType == GridElementType.DataRow && !LoggedInModel.IsDeveloper)
{
e.CssClass = "hideDetailButton";
}
}
protected void OnCustomizeElement(GridCustomizeElementEventArgs e) protected void OnCustomizeElement(GridCustomizeElementEventArgs e)
{ {
//if (!IsMasterGrid) e.CssClass = "hideDetailButton"; //if (!IsMasterGrid) e.CssClass = "hideDetailButton";
@ -50,10 +58,7 @@ public class MgGridBase : DxGrid
e.CssClass = " alt-item"; e.CssClass = " alt-item";
} }
if(e.ElementType == GridElementType.DataRow && !LoggedInModel.IsDeveloper) CustomizeElementHideDetailButton(e);
{
e.CssClass = "hideDetailButton";
}
if (e.ElementType == GridElementType.HeaderCell) if (e.ElementType == GridElementType.HeaderCell)
{ {

View File

@ -55,7 +55,7 @@ public class ShippingItemTable : SignalRDataSourceList<ShippingItemTableItem>
} }
} }
public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : FastObservableCollection<ProductDtoTableItem> public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : MgObservableCollection<ProductDtoTableItem>
{ {
private readonly SemaphoreSlim _semaphoreSlim = new(1); private readonly SemaphoreSlim _semaphoreSlim = new(1);
public async Task<ProductDtoTable> LoadDataAsync(bool onlyIfEmpty = true) public async Task<ProductDtoTable> LoadDataAsync(bool onlyIfEmpty = true)
@ -80,7 +80,7 @@ public class ProductDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : Fa
return this; return this;
} }
} }
public class OrderDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : FastObservableCollection<OrderDtoTableItem> public class OrderDtoTable(FruitBankSignalRClient fruitBankSignalRClient) : MgObservableCollection<OrderDtoTableItem>
{ {
private readonly SemaphoreSlim _semaphoreSlim = new(1); private readonly SemaphoreSlim _semaphoreSlim = new(1);

View File

@ -1,4 +1,5 @@
@page "/Login" @page "/Login"
@using FruitBank.Common.Models
@using Mango.Nop.Core.Dtos @using Mango.Nop.Core.Dtos
<h3>Bejelentkezés</h3> <h3>Bejelentkezés</h3>

View File

@ -1,6 +1,7 @@
using AyCode.Core.Loggers; using AyCode.Core.Loggers;
using AyCode.Utils.Extensions; using AyCode.Utils.Extensions;
using FruitBank.Common.Models; using FruitBank.Common.Models;
using FruitBankHybrid.Shared.Databases;
using FruitBankHybrid.Shared.Services.Loggers; using FruitBankHybrid.Shared.Services.Loggers;
using FruitBankHybrid.Shared.Services.SignalRs; using FruitBankHybrid.Shared.Services.SignalRs;
using Mango.Nop.Core.Dtos; using Mango.Nop.Core.Dtos;
@ -35,8 +36,14 @@ public partial class Login : ComponentBase
if (!LoggedInModel.IsLoggedIn) if (!LoggedInModel.IsLoggedIn)
{ {
LoggedInModel.MeasuringUsers = await FruitBankSignalRClient.GetMeasuringUsers() ?? []; using (await ObjectLock.GetSemaphore<CustomerDto>().UseWaitAsync())
SelectedUser = LoggedInModel.MeasuringUsers.FirstOrDefault(); {
if (LoggedInModel.MeasuringUsers.Count == 0)
{
LoggedInModel.MeasuringUsers = await FruitBankSignalRClient.GetMeasuringUsers() ?? [];
SelectedUser = LoggedInModel.MeasuringUsers.FirstOrDefault();
}
}
} }
else _rolesText = string.Join("; ", LoggedInModel.CustomerRoles.Select(x => x.Name)); else _rolesText = string.Join("; ", LoggedInModel.CustomerRoles.Select(x => x.Name));

View File

@ -15,6 +15,7 @@ using FruitBankHybrid.Shared.Services.Loggers;
using Mango.Nop.Core.Dtos; using Mango.Nop.Core.Dtos;
using Mango.Nop.Core.Models; using Mango.Nop.Core.Models;
using MessagePack.Resolvers; using MessagePack.Resolvers;
using Microsoft.AspNetCore.SignalR.Client;
using Nop.Core.Domain.Customers; using Nop.Core.Domain.Customers;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ServiceModel.Channels; using System.ServiceModel.Channels;
@ -25,6 +26,13 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
{ {
public FruitBankSignalRClient( /*IServiceProvider serviceProvider, */ IEnumerable<IAcLogWriterClientBase> logWriters) : base($"{FruitBankConstClient.BaseUrl}/{FruitBankConstClient.DefaultHubName}", new LoggerClient(nameof(FruitBankSignalRClient), logWriters.ToArray())) public FruitBankSignalRClient( /*IServiceProvider serviceProvider, */ IEnumerable<IAcLogWriterClientBase> logWriters) : base($"{FruitBankConstClient.BaseUrl}/{FruitBankConstClient.DefaultHubName}", new LoggerClient(nameof(FruitBankSignalRClient), logWriters.ToArray()))
{ {
//var hubConnection = new HubConnectionBuilder()
// .WithUrl("fullHubName")
// .WithAutomaticReconnect()
// .WithStatefulReconnect()
// .WithKeepAliveInterval(TimeSpan.FromSeconds(60))
// .WithServerTimeout(TimeSpan.FromSeconds(120))
ConstHelper.NameByValue<SignalRTags>(0); ConstHelper.NameByValue<SignalRTags>(0);
} }