DeliveryAdminWindow: add advanced tooltips for weight and gradation

This commit is contained in:
2023-11-07 12:54:16 +01:00
parent 493cfa3156
commit ff053e56cf
2 changed files with 99 additions and 18 deletions

View File

@ -94,7 +94,7 @@
<TextBox x:Name="SearchInput" Grid.ColumnSpan="3" Margin="5,10,161,0" IsReadOnly="False" <TextBox x:Name="SearchInput" Grid.ColumnSpan="3" Margin="5,10,161,0" IsReadOnly="False"
TextChanged="SearchInput_TextChanged" TextChanged="SearchInput_TextChanged"
ToolTip="Lieferungen filtern und durchsuchen. Die Filter sind beliebig kombinierbar.&#xA;&#xA;Filtern nach:&#xA;Sorte: z.B. GV, ZW, rr, sa, !gv (ausgenommen GV), ...&#xA;Qualitätsstufe: z.B. QUW, kab, ldw, ...&#xA;Gradation: z.B. &gt;73, &lt;15, 17-18, 15-, &gt;17,5, 62-75, ...&#xA;Mitglied: z.B. 1234, 987, ...&#xA;Saison: z.B. 2020, &gt;2015, 2017-2019, &lt;2005, 2019-, ...&#xA;Zweigstelle: z.B. musterort, ...&#xA;Attribute: z.B. kabinett, !kabinett (alle außer kabinett), ...&#xA;Datum: z.B. 1.9., 15.9.-10.10., -15.10.2020, ...&#xA;Uhrzeit: z.B. 06:00-08:00, 18:00-, ...&#xA;Freitext: z.B. Lieferscheinnummern, &quot;quw&quot; (sucht nach dem Text &quot;quw&quot;)"/> ToolTip="Lieferungen filtern und durchsuchen. Die Filter sind beliebig kombinierbar.&#xA;&#xA;Filtern nach:&#xA;Sorte: z.B. GV, ZW, rr, sa, !gv (ausgenommen GV), ...&#xA;Qualitätsstufe: z.B. QUW, kab, ldw, ...&#xA;Gradation: z.B. &gt;73, &lt;15, 17-18, 15-, &gt;17,5, 62-75, ...&#xA;Mitglied: z.B. 1234, 987, ...&#xA;Saison: z.B. 2020, &gt;2015, 2017-2019, &lt;2005, 2019-, ...&#xA;Zweigstelle: z.B. musterort, ...&#xA;Attribute: z.B. kabinett, !kabinett (alle außer kabinett), ...&#xA;Datum: z.B. 1.9., 15.9.-10.10., -15.10.2020, ...&#xA;Uhrzeit: z.B. 06:00-08:00, 18:00-, ...&#xA;Freitext: z.B. Lieferscheinnummern, &quot;quw&quot; (sucht nach dem Text &quot;quw&quot;)"/>
<xctk:IntegerUpDown Name="SeasonInput" Grid.ColumnSpan="3" Height="25" Width="56" FontSize="14" Minimum="1000" Maximum="9999" <xctk:IntegerUpDown x:Name="SeasonInput" Grid.ColumnSpan="3" Height="25" Width="56" FontSize="14" Minimum="1000" Maximum="9999"
Margin="0,10,100,0" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,10,100,0" VerticalAlignment="Top" HorizontalAlignment="Right"
ValueChanged="SeasonInput_ValueChanged"/> ValueChanged="SeasonInput_ValueChanged"/>
<CheckBox x:Name="TodayOnlyInput" Content="Nur heute" <CheckBox x:Name="TodayOnlyInput" Content="Nur heute"
@ -454,23 +454,47 @@
</ItemsPanelTemplate> </ItemsPanelTemplate>
</StatusBar.ItemsPanel> </StatusBar.ItemsPanel>
<StatusBarItem> <StatusBarItem>
<TextBlock Name="StatusMembers" Text="Mitglieder: -"/> <TextBlock x:Name="StatusMembers" Text="Mitglieder: -"/>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="1"/> <Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2"> <StatusBarItem Grid.Column="2">
<TextBlock Name="StatusDeliveries" Text="Lieferungen: -"/> <TextBlock x:Name="StatusDeliveries" Text="Lieferungen: -"/>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="3"/> <Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4"> <StatusBarItem Grid.Column="4">
<TextBlock Name="StatusVarieties" Text="Sorten: -"/> <TextBlock x:Name="StatusVarieties" Text="Sorten: -"/>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="5"/> <Separator Grid.Column="5"/>
<StatusBarItem Grid.Column="6"> <StatusBarItem Grid.Column="6">
<TextBlock Name="StatusWeight" Text="Gewicht: -"/> <TextBlock x:Name="StatusWeight" Text="Gewicht: -">
<TextBlock.ToolTip>
<Grid x:Name="StatusWeightToolTip">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
</Grid>
</TextBlock.ToolTip>
</TextBlock>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="7"/> <Separator Grid.Column="7"/>
<StatusBarItem Grid.Column="8"> <StatusBarItem Grid.Column="8">
<TextBlock Name="StatusGradation" Text="Gradation: -"/> <TextBlock x:Name="StatusGradation" Text="Gradation: -">
<TextBlock.ToolTip>
<Grid x:Name="StatusGradationToolTip">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="35"/>
<ColumnDefinition Width="35"/>
</Grid.ColumnDefinitions>
</Grid>
</TextBlock.ToolTip>
</TextBlock>
</StatusBarItem> </StatusBarItem>
</StatusBar> </StatusBar>
</Grid> </Grid>

View File

@ -519,6 +519,38 @@ namespace Elwig.Windows {
return (filterNames, dpq.Select(p => p.Delivery).Distinct().OrderBy(d => d.DateString).ThenBy(d => d.TimeString), dpq, filter); return (filterNames, dpq.Select(p => p.Delivery).Distinct().OrderBy(d => d.DateString).ThenBy(d => d.TimeString), dpq, filter);
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private void AddWeightToolTipRow(int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null;
if (h1 != null) AddToolTipCell(StatusWeightToolTip, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(StatusWeightToolTip, h2 + ":", row, 1, 1, bold);
AddToolTipCell(StatusWeightToolTip, $"{weight:N0} kg", row, 2, 1, bold, true);
if (total1 != null && total1 != 0)
AddToolTipCell(StatusWeightToolTip, $"{weight * 100.0 / total1:N1} %", row, 3, 1, bold, true);
if (total2 != 0)
AddToolTipCell(StatusWeightToolTip, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true);
}
private void AddGradationToolTipRow(int row, string? h1, string? h2, double min, double avg, double max) {
var bold = h2 == null;
if (h1 != null) AddToolTipCell(StatusGradationToolTip, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(StatusGradationToolTip, h2 + ":", row, 1, 1, bold);
AddToolTipCell(StatusGradationToolTip, $"{min:N1}°", row, 2, 1, bold, true);
AddToolTipCell(StatusGradationToolTip, $"{avg:N1}°", row, 3, 1, bold, true);
AddToolTipCell(StatusGradationToolTip, $"{max:N1}°", row, 4, 1, bold, true);
}
private async Task RefreshDeliveryListQuery(bool updateSort = false) { private async Task RefreshDeliveryListQuery(bool updateSort = false) {
var (_, deliveryQuery, deliveryPartsQuery, filter) = await GetFilters(); var (_, deliveryQuery, deliveryPartsQuery, filter) = await GetFilters();
var deliveries = await deliveryQuery.ToListAsync(); var deliveries = await deliveryQuery.ToListAsync();
@ -551,29 +583,56 @@ namespace Elwig.Windows {
var varieties = await deliveryParts.Select(d => d.SortId).Distinct().ToListAsync(); var varieties = await deliveryParts.Select(d => d.SortId).Distinct().ToListAsync();
StatusVarieties.Text = $"Sorten: {varieties.Count}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : ""); StatusVarieties.Text = $"Sorten: {varieties.Count}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : "");
StatusWeightToolTip.Children.Clear();
StatusGradationToolTip.Children.Clear();
var weight = await deliveryParts.SumAsync(p => p.Weight); var weight = await deliveryParts.SumAsync(p => p.Weight);
StatusWeight.Text = $"Gewicht: {weight:N0} kg"; StatusWeight.Text = $"Gewicht: {weight:N0} kg";
AddWeightToolTipRow(0, "Gewicht", null, weight, null, weight);
if (n > 0) { if (n > 0) {
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw); var kmwMin = await deliveryParts.MinAsync(p => p.Kmw);
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts); var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw); var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw);
StatusGradation.Text = $"Gradation: {kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°"; StatusGradation.Text = $"Gradation: {kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°";
AddToolTipCell(StatusGradationToolTip, "min.", 0, 2, 1, false, false, true);
AddToolTipCell(StatusGradationToolTip, "⌀", 0, 3, 1, false, false, true);
AddToolTipCell(StatusGradationToolTip, "max.", 0, 4, 1, false, false, true);
AddGradationToolTipRow(1, "Gradation", null, kmwMin, kmwAvg, kmwMax);
} else { } else {
StatusGradation.Text = "Gradation: -"; StatusGradation.Text = "Gradation: -";
} }
if (n > 0 && (n <= 200 || TodayOnlyInput.IsChecked == true)) { if (n > 0 && (n <= 200 || TodayOnlyInput.IsChecked == true)) {
var parts = await deliveryParts.ToListAsync(); var parts = await deliveryParts.ToListAsync();
var groups = parts var attrGroups = parts
.GroupBy(p => p.Attribute?.Name) .GroupBy(p => p.Attribute?.Name)
.Select(g => (g.Key, g.Sum(p => p.Weight), g.Min(p => p.Kmw), Utils.AggregateDeliveryPartsKmw(g), g.Max(p => p.Kmw))) .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) .OrderByDescending(g => g.Item2)
.ThenBy(g => g.Key)
.ToList();
var groups = parts
.GroupBy(p => (p.Attribute?.Name, p.SortId))
.Select(g => (g.Key.Name, g.Key.SortId, g.Sum(p => p.Weight), g.Min(p => p.Kmw), Utils.AggregateDeliveryPartsKmw(g), g.Max(p => p.Kmw)))
.OrderByDescending(g => g.SortId)
.ThenBy(g => g.Name)
.ThenBy(g => g.SortId)
.ToList(); .ToList();
if (groups.Count == 1) { int rowNum = 1;
var g = groups.First().Key; foreach (var attrG in attrGroups) {
if (g != "") { rowNum++;
AddWeightToolTipRow(rowNum++, attrG.Key, null, attrG.Item2, attrG.Item2, weight);
AddGradationToolTipRow(rowNum, attrG.Key, null, attrG.Item3, attrG.Item4, attrG.Item5);
foreach (var g in groups.Where(g => g.Name == attrG.Key).OrderByDescending(g => g.Item3).ThenBy(g => g.SortId)) {
AddWeightToolTipRow(rowNum++, null, g.SortId, g.Item3, attrG.Item2, weight);
AddGradationToolTipRow(rowNum, null, g.SortId, g.Item4, g.Item5, g.Item6);
}
}
if (attrGroups.Count == 1) {
var g = attrGroups.First().Key;
if (g != null) {
StatusWeight.Text += $" [{g}]"; StatusWeight.Text += $" [{g}]";
StatusGradation.Text += $" [{g}]"; StatusGradation.Text += $" [{g}]";
} }
@ -585,12 +644,13 @@ namespace Elwig.Windows {
.ToList(); .ToList();
if (sortGroups.Count > 1 && sortGroups.Count <= 4) { if (sortGroups.Count > 1 && sortGroups.Count <= 4) {
StatusWeight.Text += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Item2:N0} kg ({(double)g.Item2 / weight:0%})" + (g.Key == "" ? "" : $" [{g.Key}]")))}"; StatusWeight.Text += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Item2:N0} kg ({(double)g.Item2 / weight:0%})" + (g.Key == null ? "" : $" [{g.Key}]")))}";
StatusGradation.Text += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Item3:N1}/{g.Item4:N1}/{g.Item5:N1}" + (g.Key == "" ? "" : $" [{g.Key}]")))}"; StatusGradation.Text += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Item3:N1}/{g.Item4:N1}/{g.Item5:N1}" + (g.Key == null ? "" : $" [{g.Key}]")))}";
} }
} else if (groups.Count <= 4) { } else if (attrGroups.Count <= 4) {
StatusWeight.Text += $" = {string.Join(" + ", groups.Select(g => $"{g.Item2:N0} kg ({(double)g.Item2 / weight:0%})" + (g.Key == "" ? "" : $" [{g.Key}]")))}"; StatusWeight.Text += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Item2:N0} kg ({(double)g.Item2 / weight:0%})" + (g.Key == null ? "" : $" [{g.Key}]")))}";
StatusGradation.Text += $" = {string.Join(" + ", groups.Select(g => $"{g.Item3:N1}/{g.Item4:N1}/{g.Item5:N1}" + (g.Key == "" ? "" : $" [{g.Key}]")))}"; StatusGradation.Text += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Item3:N1}/{g.Item4:N1}/{g.Item5:N1}" + (g.Key == null ? "" : $" [{g.Key}]")))}";
} }
} }
} else { } else {
@ -600,9 +660,6 @@ namespace Elwig.Windows {
} }
StatusVarieties.ToolTip = StatusVarieties.Text; StatusVarieties.ToolTip = StatusVarieties.Text;
// TODO display Weight/Gradation with newlines in ToolTip and grouped by sortid AND attributes
StatusWeight.ToolTip = StatusWeight.Text;
StatusGradation.ToolTip = StatusGradation.Text;
} }
protected override async Task OnRenewContext() { protected override async Task OnRenewContext() {