Add status bar in DeliveryAdminWindow
This commit is contained in:
@ -10,6 +10,7 @@ using System.Net.Sockets;
|
||||
using Elwig.Dialogs;
|
||||
using System.Text;
|
||||
using System.Numerics;
|
||||
using Elwig.Models;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static partial class Utils {
|
||||
@ -21,6 +22,7 @@ namespace Elwig.Helpers {
|
||||
|
||||
public static readonly Regex SerialRegex = GeneratedSerialRegex();
|
||||
public static readonly Regex TcpRegex = GeneratedTcpRegex();
|
||||
public static readonly Regex PartialDateRegex = GeneratedPartialDateRegex();
|
||||
|
||||
[GeneratedRegex("^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\\.5|2|))?$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedSerialRegex();
|
||||
@ -28,6 +30,9 @@ namespace Elwig.Helpers {
|
||||
[GeneratedRegex("^tcp://([A-Za-z0-9._-]+):([0-9]+)$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedTcpRegex();
|
||||
|
||||
[GeneratedRegex(@"^(0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[0-2])\.$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedPartialDateRegex();
|
||||
|
||||
private static readonly ushort[] Crc16ModbusTable = {
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
@ -242,5 +247,15 @@ namespace Elwig.Helpers {
|
||||
0 => "\u00b1", // plus minus
|
||||
> 0 => "+",
|
||||
};
|
||||
|
||||
public static double AggregateDeliveryPartsKmw(IEnumerable<DeliveryPart> parts)
|
||||
=> parts.Aggregate(
|
||||
(Weight: 0, Kmw: 0.0),
|
||||
(sum, item) => (
|
||||
sum.Weight + item.Weight,
|
||||
(sum.Kmw * sum.Weight + item.Kmw * item.Weight) / (sum.Weight + item.Weight)
|
||||
),
|
||||
sum => sum.Kmw
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -84,20 +84,13 @@ namespace Elwig.Models {
|
||||
|
||||
public string SortIdString => string.Join(", ", SortIds);
|
||||
|
||||
public double Kmw => Parts.Aggregate(
|
||||
(Weight: 0, Kmw: 0.0),
|
||||
(sum, item) => (
|
||||
sum.Weight + item.Weight,
|
||||
(sum.Kmw * sum.Weight + item.Kmw * item.Weight) / (sum.Weight + item.Weight)
|
||||
),
|
||||
sum => sum.Kmw
|
||||
);
|
||||
public double Kmw => Utils.AggregateDeliveryPartsKmw(Parts);
|
||||
|
||||
public double Oe => Utils.KmwToOe(Kmw);
|
||||
|
||||
public int SearchScore(IEnumerable<string> keywords) {
|
||||
var list = new string?[] {
|
||||
LsNr, Date.ToString("dd.MM.yyyy"), Time?.ToString("HH:mm"),
|
||||
LsNr, Time?.ToString("HH:mm"),
|
||||
Member.FamilyName, Member.MiddleName, Member.GivenName, Member.BillingAddress?.Name,
|
||||
Comment
|
||||
}.ToList();
|
||||
|
@ -5,7 +5,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
Title="Lieferungsverwaltung - Elwig" Height="700" Width="1100" MinHeight="700" MinWidth="1000"
|
||||
Title="Lieferungsverwaltung - Elwig" Height="720" Width="1100" MinHeight="700" MinWidth="1000"
|
||||
Loaded="Window_Loaded">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
@ -47,6 +47,7 @@
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="24"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" MinWidth="400"/>
|
||||
@ -68,7 +69,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Grid Grid.RowSpan="5" Grid.Row="1" Margin="5,0,5,0">
|
||||
<Grid Grid.RowSpan="4" Grid.Row="1" Margin="5,0,5,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="42"/>
|
||||
<RowDefinition Height="*"/>
|
||||
@ -284,7 +285,7 @@
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Sonstiges" Grid.Column="2" Grid.Row="4" Margin="5,5,5,5">
|
||||
<GroupBox Header="Sonstiges" Grid.Column="2" Grid.Row="4" Margin="5,5,5,10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
@ -350,7 +351,7 @@
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Herkunft" Grid.Column="1" Grid.Row="4" Margin="5,5,5,5">
|
||||
<GroupBox Header="Herkunft" Grid.Column="1" Grid.Row="4" Margin="5,5,5,10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
@ -371,5 +372,44 @@
|
||||
DisplayMemberPath="Name"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<StatusBar Grid.Row="5" Grid.ColumnSpan="3" BorderThickness="0,1,0,0" BorderBrush="Gray">
|
||||
<StatusBar.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="3*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="3*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ItemsPanelTemplate>
|
||||
</StatusBar.ItemsPanel>
|
||||
<StatusBarItem>
|
||||
<TextBlock Name="StatusMembers" Text="Mitglieder: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="1"/>
|
||||
<StatusBarItem Grid.Column="2">
|
||||
<TextBlock Name="StatusDeliveries" Text="Lieferungen: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="3"/>
|
||||
<StatusBarItem Grid.Column="4">
|
||||
<TextBlock Name="StatusVarieties" Text="Sorten: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="5"/>
|
||||
<StatusBarItem Grid.Column="6">
|
||||
<TextBlock Name="StatusWeight" Text="Gewicht: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="7"/>
|
||||
<StatusBarItem Grid.Column="8">
|
||||
<TextBlock Name="StatusGradation" Text="Gradation: -"/>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</local:AdministrationWindow>
|
||||
|
@ -165,18 +165,21 @@ namespace Elwig.Windows {
|
||||
deliveryQuery = deliveryQuery.Where(d => d.Year == SeasonInput.Value);
|
||||
}
|
||||
|
||||
var filterVar = new List<string>();
|
||||
var filterQual = new List<string>();
|
||||
var filterMgNr = new List<int>();
|
||||
var filterDate = new List<string>();
|
||||
var filterPartDate = new List<string>();
|
||||
double filterKmwGt = 0;
|
||||
double filterKmwLt = 0;
|
||||
double filterOeGt = 0;
|
||||
double filterOeLt = 0;
|
||||
|
||||
var filter = TextFilter.ToList();
|
||||
if (filter.Count > 0) {
|
||||
var var = await Context.WineVarieties.Select(v => v.SortId).ToListAsync();
|
||||
var qual = await Context.WineQualityLevels.Select(q => q.QualId).ToListAsync();
|
||||
var mgnr = await Context.Members.Select(m => m.MgNr.ToString()).ToListAsync();
|
||||
var filterVar = new List<string>();
|
||||
var filterQual = new List<string>();
|
||||
var filterMgNr = new List<int>();
|
||||
double filterKmwGt = 0;
|
||||
double filterKmwLt = 0;
|
||||
double filterOeGt = 0;
|
||||
double filterOeLt = 0;
|
||||
|
||||
for (int i = 0; i < filter.Count; i++) {
|
||||
var e = filter[i];
|
||||
@ -190,22 +193,31 @@ namespace Elwig.Windows {
|
||||
filterMgNr.Add(int.Parse(e));
|
||||
filter.RemoveAt(i--);
|
||||
} else if (e.StartsWith(">") || e.StartsWith("<")) {
|
||||
if (double.TryParse(e[1..], out var res)) {
|
||||
switch ((e[0], res)) {
|
||||
case ('>', <= 30): filterKmwGt = res; break;
|
||||
case ('<', <= 30): filterKmwLt = res; break;
|
||||
case ('>', _): filterOeGt = res; break;
|
||||
case ('<', _): filterOeLt = res; break;
|
||||
if (double.TryParse(e[1..], out var num)) {
|
||||
switch ((e[0], num)) {
|
||||
case ('>', <= 30): filterKmwGt = num; break;
|
||||
case ('<', <= 30): filterKmwLt = num; break;
|
||||
case ('>', _): filterOeGt = num; break;
|
||||
case ('<', _): filterOeLt = num; break;
|
||||
}
|
||||
filter.RemoveAt(i--);
|
||||
}
|
||||
if (e.Length == 1) filter.RemoveAt(i--);
|
||||
} else if (DateOnly.TryParse(e, out var date)) {
|
||||
filterDate.Add($"{date:yyyy-MM-dd}");
|
||||
filter.RemoveAt(i--);
|
||||
} else if (Utils.PartialDateRegex.IsMatch(e)) {
|
||||
var parts = e.Split(".");
|
||||
filterPartDate.Add($"-{int.Parse(parts[1]):00}-{int.Parse(parts[0]):00}");
|
||||
filter.RemoveAt(i--);
|
||||
} else if (e.Length > 2 && e.StartsWith("\"") && e.EndsWith("\"")) {
|
||||
filter[i] = e[1..^1];
|
||||
}
|
||||
}
|
||||
|
||||
if (filterMgNr.Count > 0) deliveryQuery = deliveryQuery.Where(d => filterMgNr.Contains(d.MgNr));
|
||||
if (filterDate.Count > 0) deliveryQuery = deliveryQuery.Where(d => filterDate.Contains(d.DateString));
|
||||
if (filterPartDate.Count > 0) deliveryQuery = deliveryQuery.Where(d => filterPartDate.Contains(d.DateString.Substring(4)));
|
||||
if (filterVar.Count > 0) deliveryQuery = deliveryQuery.Where(d => d.Parts.Any(p => filterVar.Contains(p.SortId)));
|
||||
if (filterQual.Count > 0) deliveryQuery = deliveryQuery.Where(d => d.Parts.Any(p => filterQual.Contains(p.QualId)));
|
||||
if (filterKmwGt > 0) deliveryQuery = deliveryQuery.Where(d => d.Parts.Any(p => p.Kmw >= filterKmwGt));
|
||||
@ -228,6 +240,74 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
ControlUtils.RenewItemsSource(DeliveryList, deliveries, d => ((d as Delivery)?.Year, (d as Delivery)?.DId), DeliveryList_SelectionChanged, ControlUtils.RenewSourceDefault.IfOnly, !updateSort);
|
||||
|
||||
var members = deliveries.Select(d => d.Member).DistinctBy(m => m.MgNr).ToList();
|
||||
StatusMembers.Text = $"Mitglieder: {members.Count}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : "");
|
||||
StatusDeliveries.Text = $"Lieferungen: {deliveries.Count}";
|
||||
|
||||
if (filter.Count == 0) {
|
||||
var partsQuery = deliveryQuery.SelectMany(d => d.Parts);
|
||||
if (filterVar.Count > 0) partsQuery = partsQuery.Where(p => filterVar.Contains(p.SortId));
|
||||
if (filterQual.Count > 0) partsQuery = partsQuery.Where(p => filterQual.Contains(p.QualId));
|
||||
if (filterKmwGt > 0) partsQuery = partsQuery.Where(p => p.Kmw >= filterKmwGt);
|
||||
if (filterKmwLt > 0) partsQuery = partsQuery.Where(p => p.Kmw < filterKmwLt);
|
||||
if (filterOeGt > 0) partsQuery = partsQuery.Where(p => p.Kmw * (4.54 + 0.022 * p.Kmw) >= filterOeGt);
|
||||
if (filterOeLt > 0) partsQuery = partsQuery.Where(p => p.Kmw * (4.54 + 0.022 * p.Kmw) < filterOeLt);
|
||||
var deliveryParts = partsQuery;
|
||||
|
||||
var n = await deliveryParts.CountAsync();
|
||||
StatusDeliveries.Text = $"Lieferungen: {deliveries.Count} ({n})";
|
||||
var varieties = await deliveryParts.Select(d => d.SortId).Distinct().ToListAsync();
|
||||
StatusVarieties.Text = $"Sorten: {varieties.Count}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : "");
|
||||
|
||||
var weight = await deliveryParts.SumAsync(p => p.Weight);
|
||||
StatusWeight.Text = $"Gewicht: {weight:N0} kg";
|
||||
|
||||
if (n > 0) {
|
||||
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw);
|
||||
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
|
||||
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw);
|
||||
StatusGradation.Text = $"Gradation: {kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°";
|
||||
} else {
|
||||
StatusGradation.Text = "Gradation: -";
|
||||
}
|
||||
|
||||
|
||||
if (n > 0 && n <= 200) {
|
||||
var parts = (await deliveryParts.ToListAsync());
|
||||
var groups = parts
|
||||
.GroupBy(p => string.Join("/", p.Attributes.Select(a => a.Name)))
|
||||
.Select(g => (g.Key, g.Sum(p => p.Weight), g.Min(p => p.Kmw), Utils.AggregateDeliveryPartsKmw(g), g.Max(p => p.Kmw)))
|
||||
.OrderByDescending(g => g.Item2)
|
||||
.ToList();
|
||||
|
||||
if (groups.Count == 1) {
|
||||
var g = groups.First().Key;
|
||||
if (g != "") {
|
||||
StatusWeight.Text += $" ({g})";
|
||||
StatusGradation.Text += $" ({g})";
|
||||
}
|
||||
|
||||
var sortGroups = parts
|
||||
.GroupBy(p => p.SortId)
|
||||
.Select(g => (g.Key, g.Sum(p => p.Weight), g.Min(p => p.Kmw), Utils.AggregateDeliveryPartsKmw(g), g.Max(p => p.Kmw)))
|
||||
.OrderByDescending(g => g.Item2)
|
||||
.ToList();
|
||||
|
||||
if (sortGroups.Count > 1 && sortGroups.Count <= 4) {
|
||||
StatusWeight.Text += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Item2:N0} kg" + (g.Key == "" ? "" : $" ({g.Key})")))}";
|
||||
StatusGradation.Text += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Item3:N1}/{g.Item4:N1}/{g.Item5:N1}" + (g.Key == "" ? "" : $" ({g.Key})")))}";
|
||||
}
|
||||
} else if (groups.Count <= 4) {
|
||||
StatusWeight.Text += $" = {string.Join(" + ", groups.Select(g => $"{g.Item2:N0} kg" + (g.Key == "" ? "" : $" ({g.Key})")))}";
|
||||
StatusGradation.Text += $" = {string.Join(" + ", groups.Select(g => $"{g.Item3:N1}/{g.Item4:N1}/{g.Item5:N1}" + (g.Key == "" ? "" : $" ({g.Key})")))}";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StatusVarieties.Text = "Sorten: -";
|
||||
StatusWeight.Text = "Gewicht: -";
|
||||
StatusGradation.Text = "Gradation: -";
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task RenewContext() {
|
||||
|
Reference in New Issue
Block a user