Add MgCardView component & refactor MeasuringOut to tabs
Introduced a reusable, responsive MgCardView<TItem> 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.
This commit is contained in:
parent
ff1a5b63c1
commit
84f4990ff4
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<h3>Áru bevételezés</h3>
|
||||
|
||||
<div style="margin-top: 50px;">
|
||||
<div style="margin-top: 30px;">
|
||||
<DxLoadingPanel @bind-Visible="LoadingPanelVisible"
|
||||
IsContentBlocked="true"
|
||||
ApplyBackgroundShading="true"
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
@using FruitBank.Common.SignalRs
|
||||
@using FruitBankHybrid.Shared.Components
|
||||
@using FruitBankHybrid.Shared.Services
|
||||
@using AyCode.Blazor.Components.Components.CardViews
|
||||
@using Nop.Core.Domain.Orders
|
||||
<h3>Áru kiadás</h3>
|
||||
|
||||
<DxDialogProvider />
|
||||
|
||||
<div style="margin-top: 50px;">
|
||||
|
||||
<div style="margin-top: 30px;">
|
||||
<DxLoadingPanel @bind-Visible="LoadingPanelVisible"
|
||||
IsContentBlocked="true"
|
||||
ApplyBackgroundShading="true"
|
||||
|
|
@ -22,231 +22,267 @@
|
|||
IndicatorAnimationType="WaitIndicatorAnimationType.Spin"
|
||||
Text="Adatok szinkronizálása folyamatban...">
|
||||
|
||||
<DxFormLayout CaptionPosition="CaptionPosition.Vertical" CssClass="w-100">
|
||||
<DxFormLayoutItem Caption="Dátum" ColSpanMd="3"
|
||||
<DxFormLayout CaptionPosition="CaptionPosition.Vertical" CssClass="w-100 measuring-form-layout">
|
||||
<DxFormLayoutItem Caption="Dátum" ColSpanXs="8" ColSpanSm="8" ColSpanMd="2"
|
||||
CaptionCssClass="@(SelectedOrder != null && _measuringDates.Where(x => MeasurementService.DaysEqual(x.DateTime, SelectedOrder.DateOfReceiptOrCreated)).All(x => x.IsMeasured) ? "text-success" : "")">
|
||||
<div class="container-fluid p-0">
|
||||
<div class="row">
|
||||
<div class="col-9 p-0">
|
||||
<DxDateEdit DisplayFormat="m"
|
||||
Format="m"
|
||||
Context="ctxOrderDate"
|
||||
Date="@(SelectedOrder?.DateOfReceiptOrCreated.Date ?? DateTime.Now.Date)"
|
||||
CustomDisabledDate="@OnCustomDisabledMeasuringDate"
|
||||
DateChanged="@((DateTime newValue) => OnMeasuringDateChanged(newValue))"
|
||||
InputId="deDisabledDates"
|
||||
PickerDisplayMode="DatePickerDisplayMode.Calendar">
|
||||
<DayCellTemplate>
|
||||
@{
|
||||
var cssClass = GetMeasuringDateCssClassNames(ctxOrderDate);
|
||||
if (!cssClass.IsNullOrWhiteSpace())
|
||||
{
|
||||
<a class="@GetMeasuringDateCssClassNames(ctxOrderDate)">@ctxOrderDate.Day.ToString()</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a>@ctxOrderDate.Day.ToString()</a>
|
||||
}
|
||||
}
|
||||
</DayCellTemplate>
|
||||
</DxDateEdit>
|
||||
</div>
|
||||
<div class="col-3 p-0">
|
||||
<DxSpinEdit T="int" Value="1" Increment="1" MinValue="1" ValueChanged="async i => await RefreshOrdersFromDb(DateTime.Now, i)"></DxSpinEdit>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DxDateEdit DisplayFormat="m"
|
||||
Format="m"
|
||||
Context="ctxOrderDate"
|
||||
Date="@(SelectedOrder?.DateOfReceiptOrCreated.Date ?? DateTime.Now.Date)"
|
||||
CustomDisabledDate="@OnCustomDisabledMeasuringDate"
|
||||
DateChanged="@((DateTime newValue) => OnMeasuringDateChanged(newValue))"
|
||||
InputId="deDisabledDates"
|
||||
PickerDisplayMode="DatePickerDisplayMode.Calendar">
|
||||
<DayCellTemplate>
|
||||
@{
|
||||
var cssClass = GetMeasuringDateCssClassNames(ctxOrderDate);
|
||||
if (!cssClass.IsNullOrWhiteSpace())
|
||||
{
|
||||
<a class="@GetMeasuringDateCssClassNames(ctxOrderDate)">@ctxOrderDate.Day.ToString()</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a>@ctxOrderDate.Day.ToString()</a>
|
||||
}
|
||||
}
|
||||
</DayCellTemplate>
|
||||
</DxDateEdit>
|
||||
</DxFormLayoutItem>
|
||||
|
||||
<DxFormLayoutItem Caption="Átvétel időpontja:" ColSpanMd="5" CaptionCssClass="@(SelectedOrder?.IsMeasured == true ? "text-success" : "")">
|
||||
<DxComboBox Data="@SelectedDayOrders"
|
||||
@bind-Value="@SelectedOrder"
|
||||
Text="Válasszon időpontot..."
|
||||
ValueFieldName="@nameof(OrderDto.Id)"
|
||||
TextFieldName="@nameof(OrderDto.TimeOfReceiptText)"
|
||||
CssClass="cw-480"
|
||||
Context="ctxOrder"
|
||||
DropDownBodyCssClass="dd-body-class"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains"
|
||||
SearchTextParseMode="ListSearchTextParseMode.GroupWordsByAnd"
|
||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
|
||||
DropDownTriggerMode="DropDownTriggerMode.Click"
|
||||
ListRenderMode="ListRenderMode.Entire"
|
||||
ShowDropDownButton="false"
|
||||
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<OrderDto> args) => OnSelectedOrderChanged(args))"
|
||||
InputId="cbOrders">
|
||||
<ItemDisplayTemplate>
|
||||
<span class="@(ctxOrder.DataItem.IsMeasured ? "text-success" : "")">@ctxOrder.DisplayText</span>
|
||||
</ItemDisplayTemplate>
|
||||
<Buttons>
|
||||
<DxEditorButton IconCssClass="editor-icon editor-icon-add" Text="R" Tooltip="Adatok frissítése..."
|
||||
Click="() => OnOrdersRefreshClick()" />
|
||||
</Buttons>
|
||||
</DxComboBox>
|
||||
<DxFormLayoutItem Caption="Napok száma" ColSpanXs="4" ColSpanSm="4" ColSpanMd="1">
|
||||
<DxSpinEdit T="int" Value="1" Increment="1" MinValue="1"
|
||||
ValueChanged="async i => await RefreshOrdersFromDb(DateTime.Now, i)" />
|
||||
</DxFormLayoutItem>
|
||||
|
||||
@if (SelectedOrder == null)
|
||||
{
|
||||
<DxFormLayoutItem ColSpanMd="2" />
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedOrder is { MeasurementOwnerId: 0, IsComplete: false } && HasMeasuringAccess)
|
||||
{
|
||||
<DxFormLayoutItem ColSpanMd="2">
|
||||
<DxButton Enabled="@(HasMeasuringAccess && SelectedOrder?.MeasurementOwnerId == 0)" Visible="(SelectedOrder != null)"
|
||||
CssClass="w-100"
|
||||
Text="@(HasMeasuringAccess && SelectedOrder?.MeasurementOwnerId == 0 ? " Indítás" : "Folyamatban...")"
|
||||
Click="() => OnStartMeasuringClick()" />
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
else
|
||||
{
|
||||
<DxFormLayoutItem ColSpanMd="2" Caption="Indította" CaptionCssClass="@(SelectedOrder?.IsMeasured == true ? " text-success" : "")">
|
||||
<DxTextBox Enabled="false" Text="@(LoggedInModel.MeasuringUsers.FirstOrDefault(x => x.Id == SelectedOrder?.MeasurementOwnerId)?.LastName)" />
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
}
|
||||
|
||||
@* <DxFormLayoutItem ColSpanMd="1"></DxFormLayoutItem> *@
|
||||
@if (SelectedOrder != null && LoggedInModel.IsRevisor)
|
||||
{
|
||||
var isCompleteOrder = SelectedOrder.IsComplete;
|
||||
|
||||
<DxFormLayoutItem Caption="Revizor:" ColSpanMd="2" CaptionCssClass="@(isCompleteOrder ? "text-success" : "")">
|
||||
<DxButton Text="@(isCompleteOrder ? "Lezárva" : "Lezárás")"
|
||||
Enabled="@(!isCompleteOrder && IsAllOrderItemPalletAudited)" CssClass="w-100"
|
||||
Click="() => OnMeasuringAuditorClick()" />
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
</DxFormLayout>
|
||||
|
||||
@if (SelectedOrder == null || LoadingPanelVisible)
|
||||
{
|
||||
}
|
||||
else if (!HasMeasuringAccess)
|
||||
{
|
||||
<div style="margin-top: 30px;">
|
||||
<H3>Mások végzik a mérést!</H3>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
string? orderNote;
|
||||
if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x => x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace())
|
||||
{
|
||||
<div class="container-fluid p-0" style="margin-top: 20px">
|
||||
<b> Megjegyzés: </b><span>@(orderNote) </span>
|
||||
<DxTabs ActiveTabIndex="(int)_activeTab" ActiveTabIndexChanged="i => _activeTab = (MeasuringTab)i" RenderMode="TabsRenderMode.OnDemand" CssClass="measuring-tabs">
|
||||
<DxTabPage Text="Napi feladatok">
|
||||
<div class="p-3">
|
||||
<MgCardView TItem="OrderDto" Data="@FilteredOrders"
|
||||
ShowFilterPanel="true"
|
||||
OnCardClick="NavigateToMeasuringTab">
|
||||
<FilterPanel>
|
||||
<DxTagBox Data="@(Enum.GetValues<MeasuringStatus>())"
|
||||
NullText="Összes státusz"
|
||||
@bind-Values="_statusFilter"
|
||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
|
||||
CssClass="cw-480" />
|
||||
</FilterPanel>
|
||||
<CardTemplate>
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h6 class="mb-0">#@context.CustomOrderNumber</h6>
|
||||
<span class="badge @GetOrderStatusBadgeCssClass(context.MeasuringStatus)">@GetOrderStatusText(context.MeasuringStatus)</span>
|
||||
</div>
|
||||
<div class="text-muted small mb-2">
|
||||
<strong>@context.DateOfReceiptOrCreated.ToString("H:mm")</strong> — @context.Customer.Company
|
||||
</div>
|
||||
@foreach (var item in context.OrderItemDtos)
|
||||
{
|
||||
<div class="@GetOrderStatusCssClass(item.MeasuringStatus) small">
|
||||
@item.ProductName — @item.TrayQuantity/@item.Quantity rekesz
|
||||
</div>
|
||||
}
|
||||
</CardTemplate>
|
||||
</MgCardView>
|
||||
</div>
|
||||
}
|
||||
</DxTabPage>
|
||||
<DxTabPage Text="Mérés">
|
||||
<div class="p-3">
|
||||
<DxFormLayout CaptionPosition="CaptionPosition.Vertical" CssClass="w-100">
|
||||
<DxFormLayoutItem Caption="Átvétel időpontja:" ColSpanMd="5" CaptionCssClass="@(SelectedOrder?.IsMeasured == true ? "text-success" : "")">
|
||||
<DxComboBox Data="@SelectedDayOrders"
|
||||
@bind-Value="@SelectedOrder"
|
||||
Text="Válasszon időpontot..."
|
||||
ValueFieldName="@nameof(OrderDto.Id)"
|
||||
TextFieldName="@nameof(OrderDto.TimeOfReceiptText)"
|
||||
CssClass="cw-480"
|
||||
Context="ctxOrder"
|
||||
DropDownBodyCssClass="dd-body-class"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains"
|
||||
SearchTextParseMode="ListSearchTextParseMode.GroupWordsByAnd"
|
||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
|
||||
DropDownTriggerMode="DropDownTriggerMode.Click"
|
||||
ListRenderMode="ListRenderMode.Entire"
|
||||
ShowDropDownButton="true"
|
||||
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<OrderDto> args) => OnSelectedOrderChanged(args))"
|
||||
InputId="cbOrders">
|
||||
<ItemDisplayTemplate>
|
||||
<span class="@(ctxOrder.DataItem.IsMeasured ? "text-success" : "")">@ctxOrder.DisplayText</span>
|
||||
</ItemDisplayTemplate>
|
||||
<Buttons>
|
||||
<DxEditorButton IconCssClass="editor-icon editor-icon-add" Text="R" Tooltip="Adatok frissítése..."
|
||||
Click="() => OnOrdersRefreshClick()" />
|
||||
</Buttons>
|
||||
</DxComboBox>
|
||||
</DxFormLayoutItem>
|
||||
|
||||
<div style="margin-top: 30px;">
|
||||
<h4 style="margin-bottom: 30px;" class="@(SelectedOrder?.IsMeasured == true ? "text-success" : "")">
|
||||
Rendelés azonosító: #@(SelectedOrder?.CustomOrderNumber)
|
||||
</h4>
|
||||
|
||||
<DxAccordion Data="@SelectedOrder?.OrderItemDtos" Enabled="@((HasMeasuringAccess && SelectedOrder?.MeasurementOwnerId > 0 && (LoggedInModel.IsRevisor || !(SelectedOrder?.IsComplete ?? false))))"
|
||||
ExpandMode="AccordionExpandMode.SingleOrNone"
|
||||
ExpandCollapseAction="AccordionExpandCollapseAction.ExpandButtonClick"
|
||||
AnimationType="LayoutAnimationType.Slide">
|
||||
<DataMappings>
|
||||
<DxAccordionDataMapping Text=ProductName></DxAccordionDataMapping>
|
||||
@* <DxAccordionDataMapping Text="OrderItemId" Level="1"></DxAccordionDataMapping> *@
|
||||
</DataMappings>
|
||||
<ItemHeaderTextTemplate>
|
||||
@{
|
||||
if (context.Level == 0)
|
||||
@if (SelectedOrder == null)
|
||||
{
|
||||
<DxFormLayoutItem ColSpanMd="5">
|
||||
<div class="alert alert-info mt-2" role="alert">
|
||||
<i class="me-1">ℹ</i> Válasszon ki egy rendelést a mérés indításához.
|
||||
</div>
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
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;
|
||||
|
||||
<h5 class="@cssClass">@(displayText)</h5>
|
||||
<DxFormLayoutItem ColSpanMd="2">
|
||||
<DxButton Enabled="@(HasMeasuringAccess && SelectedOrder?.MeasurementOwnerId == 0)" Visible="(SelectedOrder != null)"
|
||||
CssClass="w-100"
|
||||
Text="@(HasMeasuringAccess && SelectedOrder?.MeasurementOwnerId == 0 ? "Indítás" : "Folyamatban...")"
|
||||
Click="() => OnStartMeasuringClick()" />
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
else
|
||||
{
|
||||
<DxFormLayoutItem ColSpanMd="2" Caption="Indította" CaptionCssClass="@(SelectedOrder?.IsMeasured == true ? "text-success" : "")">
|
||||
<DxTextBox Enabled="false" Text="@(LoggedInModel.MeasuringUsers.FirstOrDefault(x => x.Id == SelectedOrder?.MeasurementOwnerId)?.LastName)" />
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
}
|
||||
</ItemHeaderTextTemplate>
|
||||
<ItemContentTemplate>
|
||||
@{
|
||||
if (context.Level == 0)
|
||||
{
|
||||
var selectedOrderItem = (OrderItemDto)(context.DataItem);
|
||||
|
||||
<DxFormLayout Context="ctxFormLayout" Data="@selectedOrderItem" CaptionPosition="CaptionPosition.Vertical"
|
||||
CssClass="w-100">
|
||||
<DxFormLayoutItem Context="ctxFormLayoutItem" ColSpanMd="12">
|
||||
@for (var index = 0; index < (selectedOrderItem?.OrderItemPallets?.Count ?? 0); index++)
|
||||
@if (SelectedOrder != null && LoggedInModel.IsRevisor)
|
||||
{
|
||||
var isCompleteOrder = SelectedOrder.IsComplete;
|
||||
|
||||
<DxFormLayoutItem Caption="Revizor:" ColSpanMd="2" CaptionCssClass="@(isCompleteOrder ? "text-success" : "")">
|
||||
<DxButton Text="@(isCompleteOrder ? "Lezárva" : "Lezárás")"
|
||||
Enabled="@(!isCompleteOrder && IsAllOrderItemPalletAudited)" CssClass="w-100"
|
||||
Click="() => OnMeasuringAuditorClick()" />
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
</DxFormLayout>
|
||||
|
||||
@if (SelectedOrder == null || LoadingPanelVisible)
|
||||
{
|
||||
}
|
||||
else if (!HasMeasuringAccess)
|
||||
{
|
||||
<div class="alert alert-warning mt-4" role="alert">
|
||||
<strong>⚠ Figyelem!</strong> Jelenleg más felhasználó végzi a mérést ennél a rendelésnél.
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
string? orderNote;
|
||||
if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x => x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace())
|
||||
{
|
||||
<div class="alert alert-info mt-3" role="alert">
|
||||
<strong>📝 Megjegyzés:</strong> @(orderNote)
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="mt-5">
|
||||
<h4 class="mb-1 @(SelectedOrder?.IsMeasured == true ? "text-success" : "")">
|
||||
Rendelés azonosító: #@(SelectedOrder?.CustomOrderNumber)
|
||||
</h4>
|
||||
|
||||
<DxAccordion Data="@SelectedOrder?.OrderItemDtos" Enabled="@((HasMeasuringAccess && SelectedOrder?.MeasurementOwnerId > 0 && (LoggedInModel.IsRevisor || !(SelectedOrder?.IsComplete ?? false))))"
|
||||
ExpandMode="AccordionExpandMode.SingleOrNone"
|
||||
ExpandCollapseAction="AccordionExpandCollapseAction.ExpandButtonClick"
|
||||
AnimationType="LayoutAnimationType.Slide">
|
||||
<DataMappings>
|
||||
<DxAccordionDataMapping Text=ProductName></DxAccordionDataMapping>
|
||||
</DataMappings>
|
||||
<ItemHeaderTextTemplate>
|
||||
@{
|
||||
if (context.Level == 0)
|
||||
{
|
||||
var localI = index + 1;
|
||||
var currentOrderItemPallet = selectedOrderItem!.OrderItemPallets![index];
|
||||
var cssClass = "text-danger";
|
||||
|
||||
<PalletItemComponent IsMeasurable="@selectedOrderItem.IsMeasurable"
|
||||
MeasuringIndex="@localI"
|
||||
Editable="@(_enablePalletItems && !currentOrderItemPallet.IsAudited && !(SelectedOrder?.IsComplete ?? false))"
|
||||
PalletItem="@currentOrderItemPallet"
|
||||
ProductId="@selectedOrderItem.ProductId"
|
||||
MaxTrayQuantity="@selectedOrderItem.Quantity"
|
||||
AddOrUpdateSignalRTag="SignalRTags.AddOrUpdateMeasuredOrderItemPallet"
|
||||
OnPalletItemSaveOrAuditClick="pallet => OnOrderItemSaveOrAuditClick(pallet, selectedOrderItem)"
|
||||
OnPalletItemSaved="pallet => OnOrderItemPalletSaved(pallet, selectedOrderItem)"
|
||||
OnPalletItemValueChanged="pallet => OnOrderItemPalletValueChanged(pallet, selectedOrderItem)"
|
||||
OnPalletItemAudited="pallet => OnOrderItemAudited(pallet, selectedOrderItem)">
|
||||
</PalletItemComponent>
|
||||
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;
|
||||
|
||||
<h5 class="@cssClass">@(displayText)</h5>
|
||||
}
|
||||
</DxFormLayoutItem>
|
||||
|
||||
<DxFormLayoutItem Context="ctxFromLayoutNewPallet" ColSpanMd="2" BeginRow="true">
|
||||
<DxButton Text="Új sor" Click="() => AddNewPalletItemClick(selectedOrderItem)" CssClass="w-100"
|
||||
Visible="@(!(SelectedOrder?.IsComplete ?? false))"
|
||||
Enabled="@(selectedOrderItem.OrderItemPallets[^1].Id > 0)" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="ctxFromLayoutNewPallet" ColSpanMd="3">
|
||||
<DxButton Text="Utolsó sor törlése" Click="() => LastPalletItemDeleteClick(selectedOrderItem)" CssClass="w-100"
|
||||
Visible="@(!(SelectedOrder?.IsComplete ?? false))"
|
||||
Enabled="@(selectedOrderItem.OrderItemPallets.Count > 1 && selectedOrderItem.OrderItemPallets[^1].Id <= 0)" />
|
||||
</DxFormLayoutItem>
|
||||
|
||||
<DxFormLayoutItem Context="ctxFromLayoutNewPallet" ColSpanMd="7" />
|
||||
|
||||
<DxFormLayoutItem Context="vfdfgfd" ColSpanMd="12" BeginRow="true">
|
||||
<DxFormLayout CssClass="w-100" Context="dfcadsc">
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false"><strong>TOTAL:</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false" />
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false" />
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false" />
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false"><strong>Rekesz: @(selectedOrderItem.TrayQuantity) db</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false"><strong>Br: @(selectedOrderItem.GrossWeight) kg</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false"><strong>Net: @(selectedOrderItem.NetWeight) kg</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false" />
|
||||
</DxFormLayout>
|
||||
</DxFormLayoutItem>
|
||||
|
||||
@if (!_errorText.IsNullOrWhiteSpace())
|
||||
{
|
||||
<DxFormLayoutItem Context="ctxFromLayoutItemError" ColSpanMd="12" BeginRow="true">
|
||||
<text>HIBA! @_errorText</text>
|
||||
</DxFormLayoutItem>
|
||||
//_errorText = string.Empty;
|
||||
}
|
||||
</DxFormLayout>
|
||||
<div style="margin-bottom: 20px;"></div>
|
||||
}
|
||||
}
|
||||
</ItemContentTemplate>
|
||||
</DxAccordion>
|
||||
</div>
|
||||
}
|
||||
</ItemHeaderTextTemplate>
|
||||
<ItemContentTemplate>
|
||||
@{
|
||||
if (context.Level == 0)
|
||||
{
|
||||
var selectedOrderItem = (OrderItemDto)(context.DataItem);
|
||||
|
||||
<DxFormLayout Context="ctxFormLayout" Data="@selectedOrderItem" CaptionPosition="CaptionPosition.Vertical"
|
||||
CssClass="w-100">
|
||||
<DxFormLayoutItem Context="ctxFormLayoutItem" ColSpanMd="12">
|
||||
@for (var index = 0; index < (selectedOrderItem?.OrderItemPallets?.Count ?? 0); index++)
|
||||
{
|
||||
var localI = index + 1;
|
||||
var currentOrderItemPallet = selectedOrderItem!.OrderItemPallets![index];
|
||||
|
||||
<PalletItemComponent IsMeasurable="@selectedOrderItem.IsMeasurable"
|
||||
MeasuringIndex="@localI"
|
||||
Editable="@(_enablePalletItems && !currentOrderItemPallet.IsAudited && !(SelectedOrder?.IsComplete ?? false))"
|
||||
PalletItem="@currentOrderItemPallet"
|
||||
ProductId="@selectedOrderItem.ProductId"
|
||||
MaxTrayQuantity="@selectedOrderItem.Quantity"
|
||||
AddOrUpdateSignalRTag="SignalRTags.AddOrUpdateMeasuredOrderItemPallet"
|
||||
OnPalletItemSaveOrAuditClick="pallet => OnOrderItemSaveOrAuditClick(pallet, selectedOrderItem)"
|
||||
OnPalletItemSaved="pallet => OnOrderItemPalletSaved(pallet, selectedOrderItem)"
|
||||
OnPalletItemValueChanged="pallet => OnOrderItemPalletValueChanged(pallet, selectedOrderItem)"
|
||||
OnPalletItemAudited="pallet => OnOrderItemAudited(pallet, selectedOrderItem)">
|
||||
</PalletItemComponent>
|
||||
}
|
||||
</DxFormLayoutItem>
|
||||
|
||||
<DxFormLayoutItem Context="ctxFromLayoutNewPallet" ColSpanMd="2" BeginRow="true">
|
||||
<DxButton Text="Új sor" Click="() => AddNewPalletItemClick(selectedOrderItem)" CssClass="w-100"
|
||||
Visible="@(!(SelectedOrder?.IsComplete ?? false))"
|
||||
Enabled="@(selectedOrderItem.OrderItemPallets[^1].Id > 0)" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="ctxFromLayoutNewPallet" ColSpanMd="3">
|
||||
<DxButton Text="Utolsó sor törlése" Click="() => LastPalletItemDeleteClick(selectedOrderItem)" CssClass="w-100"
|
||||
Visible="@(!(SelectedOrder?.IsComplete ?? false))"
|
||||
Enabled="@(selectedOrderItem.OrderItemPallets.Count > 1 && selectedOrderItem.OrderItemPallets[^1].Id <= 0)" />
|
||||
</DxFormLayoutItem>
|
||||
|
||||
<DxFormLayoutItem Context="ctxFromLayoutNewPallet" ColSpanMd="7" />
|
||||
|
||||
<DxFormLayoutItem Context="vfdfgfd" ColSpanMd="12" BeginRow="true">
|
||||
<DxFormLayout CssClass="w-100" Context="dfcadsc">
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false"><strong>TOTAL:</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false" />
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false" />
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false" />
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false"><strong>Rekesz: @(selectedOrderItem.TrayQuantity) db</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="2" BeginRow="false"><strong>Br: @(selectedOrderItem.GrossWeight) kg</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false"><strong>Net: @(selectedOrderItem.NetWeight) kg</strong></DxFormLayoutItem>
|
||||
<DxFormLayoutItem Context="dfcadsc2" ColSpanMd="1" BeginRow="false" />
|
||||
</DxFormLayout>
|
||||
</DxFormLayoutItem>
|
||||
|
||||
@if (!_errorText.IsNullOrWhiteSpace())
|
||||
{
|
||||
<DxFormLayoutItem Context="ctxFromLayoutItemError" ColSpanMd="12" BeginRow="true">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<strong>⚠ Hiba:</strong> @_errorText
|
||||
</div>
|
||||
</DxFormLayoutItem>
|
||||
}
|
||||
</DxFormLayout>
|
||||
<div class="mb-3"></div>
|
||||
}
|
||||
}
|
||||
</ItemContentTemplate>
|
||||
</DxAccordion>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</DxTabPage>
|
||||
</DxTabs>
|
||||
</DxLoadingPanel>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -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<MeasuringStatus> _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<MeasuringDateSelectorModel> _measuringDates = null!;
|
||||
|
||||
private IReadOnlyList<OrderDto> 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<OrderDto> 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
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
private async Task NavigateToMeasuringTab(OrderDto order)
|
||||
{
|
||||
LoadingPanelVisible = true;
|
||||
SelectedOrder = order;
|
||||
|
||||
await RefreshOrderStatusFromDbAsync(order);
|
||||
|
||||
_activeTab = MeasuringTab.Measuring;
|
||||
|
||||
await ApplyMeasuringAccessAsync(order);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the latest order data from DB and updates status and generic attributes.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets measuring access, hides loading panel, refreshes UI, and shows info dialog if access is denied.
|
||||
/// </summary>
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue