From 7fef895491a746ec5d87be1a73fd8adaa3803856 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Wed, 16 Sep 2026 17:28:38 +0200 Subject: [PATCH] DeliveryService: Add red/white distinction to tool tips --- Elwig/Helpers/Extensions.cs | 4 +- Elwig/Services/DeliveryService.cs | 153 ++++++++++++++++++++---------- 2 files changed, 106 insertions(+), 51 deletions(-) diff --git a/Elwig/Helpers/Extensions.cs b/Elwig/Helpers/Extensions.cs index f0e348c..8df01f8 100644 --- a/Elwig/Helpers/Extensions.cs +++ b/Elwig/Helpers/Extensions.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Media; namespace Elwig.Helpers { public static partial class Extensions { @@ -192,13 +193,14 @@ namespace Elwig.Helpers { } } - public static void AddToolTipCell(this Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) { + public static void AddToolTipCell(this Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false, Brush? color = null) { 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, }; + if (color != null) tb.Foreground = color; tb.SetValue(Grid.ColumnProperty, col); tb.SetValue(Grid.ColumnSpanProperty, colSpan); grid.Children.Add(tb); diff --git a/Elwig/Services/DeliveryService.cs b/Elwig/Services/DeliveryService.cs index abc0fa8..8ba4138 100644 --- a/Elwig/Services/DeliveryService.cs +++ b/Elwig/Services/DeliveryService.cs @@ -1,19 +1,21 @@ using Elwig.Documents; -using Elwig.Helpers.Export; using Elwig.Helpers; +using Elwig.Helpers.Export; using Elwig.Models.Dtos; using Elwig.Models.Entities; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System; using Elwig.ViewModels; +using iText.Commons.Internal.Runtime; using LinqKit; -using System.Globalization; -using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; using System.Windows.Controls; +using System.Windows.Media; namespace Elwig.Services { public static class DeliveryService { @@ -975,30 +977,40 @@ namespace Elwig.Services { } } - private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) { - var bold = h2 == null; - if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); - if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold); - grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true); + private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, string? h3, int weight, int? total1, int? total2, int total3, string? type) { + var bold = h3 == null; + var color = type == "R" ? Brushes.Firebrick : type == "W" ? Brushes.ForestGreen : null; + if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? (h3 == null) ? 3 : 2 : 1, bold: bold, color: color); + if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, (h3 == null) ? 2 : 1, bold: bold, color: color); + if (h3 != null) grid.AddToolTipCell(h3 + ":", row, 2, 1, bold: bold, color: color); + grid.AddToolTipCell($"{weight:N0} kg", row, 3, bold: bold, alignRight: true, color: color); if (total1 != null && total1 != 0) - grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true); - if (total2 != 0) - grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true); + grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 4, bold: bold, alignRight: true, color: color); + if (total2 != null && total2 != 0) + grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 5, bold: bold, alignRight: true, color: color); + if (total3 != 0) + grid.AddToolTipCell($"{weight * 100.0 / total3:N1} %", row, 6, bold: bold, alignRight: true, color: color); } - private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) { - var bold = h2 == null; - if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); - if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold); - grid.AddToolTipCell($"{min:N1}°", row, 2, bold: bold, alignRight: true); - grid.AddToolTipCell($"{avg:N1}°", row, 3, bold: bold, alignRight: true); - grid.AddToolTipCell($"{max:N1}°", row, 4, bold: bold, alignRight: true); + private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, string? h3, double min, double avg, double max, string? type) { + var bold = h3 == null; + var color = type == "R" ? Brushes.Firebrick : type == "W" ? Brushes.ForestGreen : null; + if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? (h3 == null) ? 3 : 2 : 1, bold: bold, color: color); + if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, (h3 == null) ? 2 : 1, bold: bold, color: color); + if (h3 != null) grid.AddToolTipCell(h3 + ":", row, 2, bold: bold, color: color); + grid.AddToolTipCell($"{min:N1}°", row, 3, bold: bold, alignRight: true, color: color); + grid.AddToolTipCell($"{avg:N1}°", row, 4, bold: bold, alignRight: true, color: color); + grid.AddToolTipCell($"{max:N1}°", row, 5, bold: bold, alignRight: true, color: color); } - public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable deliveryParts) { - var wGrid = new List<(string?, string?, int, int?, int)>(); + private static string? GetGroupName(params string?[] parts) { + return parts.All(p => p == null) ? null : string.Join(" / ", parts.Where(p => p != null)); + } + + public static async Task<(string WeightText, (string?, string?, string?, int, int?, int?, int, string?)[] WeightGrid, string GradationText, (string?, string?, string?, double, double, double, string?)[] GradationGrid)> GenerateToolTipData(IQueryable deliveryParts) { + var wGrid = new List<(string?, string?, string?, int, int?, int?, int, string?)>(); var wText = "-"; - var gGrid = new List<(string?, string?, double, double, double)>(); + var gGrid = new List<(string?, string?, string?, double, double, double, string?)>(); var gText = "-"; var stat = (await deliveryParts.GroupBy(p => 0) @@ -1013,11 +1025,11 @@ namespace Elwig.Services { .Single(); wText = $"{stat.Weight:N0} kg"; - wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight)); + wGrid.Add(("Menge", null, null, stat.Weight, null, null, stat.Weight, null)); if (stat.Min != null && stat.Max != null) { gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°"; - gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value)); + gGrid.Add(("Gradation", null, null, stat.Min.Value, stat.Avg, stat.Max.Value, null)); var attrGroups = await deliveryParts .GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name }) @@ -1034,9 +1046,10 @@ namespace Elwig.Services { .ThenBy(g => g.Cult) .ToListAsync(); var sortGroups = await deliveryParts - .GroupBy(p => p.SortId) + .GroupBy(p => new { p.SortId, p.Variety.Type }) .Select(g => new { - SortId = g.Key, + g.Key.SortId, + g.Key.Type, Weight = g.Sum(p => p.Weight), Min = g.Min(p => p.Kmw), Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight), @@ -1049,11 +1062,13 @@ namespace Elwig.Services { .GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name, + p.Variety.Type, p.SortId, }) .Select(g => new { g.Key.Attr, g.Key.Cult, + g.Key.Type, g.Key.SortId, Weight = g.Sum(p => p.Weight), Min = g.Min(p => p.Kmw), @@ -1063,27 +1078,62 @@ namespace Elwig.Services { .OrderByDescending(g => g.Weight) .ThenBy(g => g.Attr) .ThenBy(g => g.Cult) + .ThenBy(g => g.Type) .ThenBy(g => g.SortId) .ToListAsync(); foreach (var attrG in attrGroups) { - var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; - wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight)); - foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { - wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight)); + var name = GetGroupName(attrG.Attr, attrG.Cult); + var typeGroups = groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult) + .GroupBy(g => g.Type) + .Select(g => new { Type = g.Key, Weight = g.Sum(p => p.Weight) }) + .OrderByDescending(g => g.Weight).ThenBy(g => g.Type) + .ToList(); + wGrid.Add((name, null, null, attrG.Weight, null, attrG.Weight, stat.Weight, typeGroups.Count == 1 ? typeGroups.First().Type : null)); + if (typeGroups.Count == 1) { + foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { + wGrid.Add((null, null, g.SortId, g.Weight, null, attrG.Weight, stat.Weight, null)); + } + } else { + foreach (var t in typeGroups) { + wGrid.Add((null, t.Type == "R" ? "Rot" : "Weiß", null, t.Weight, t.Weight, attrG.Weight, stat.Weight, t.Type)); + foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult && g.Type == t.Type).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { + wGrid.Add((null, null, g.SortId, g.Weight, t.Weight, attrG.Weight, stat.Weight, null)); + } + } } } foreach (var attrG in attrGroups) { - var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; - gGrid.Add((name, null, attrG.Min, attrG.Avg, attrG.Max)); - foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) { - gGrid.Add((null, g.SortId, g.Min, g.Avg, g.Max)); + var name = GetGroupName(attrG.Attr, attrG.Cult); + var typeGroups = groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult) + .GroupBy(g => g.Type) + .Select(g => new { + Type = g.Key, + Weight = g.Sum(p => p.Weight), + Min = g.Min(p => p.Min), + Avg = g.Sum(p => p.Avg * p.Weight) / g.Sum(p => p.Weight), + Max = g.Max(p => p.Max), + }) + .OrderByDescending(g => g.Weight).ThenBy(g => g.Type) + .ToList(); + gGrid.Add((name, null, null, attrG.Min, attrG.Avg, attrG.Max, typeGroups.Count == 1 ? typeGroups.First().Type : null)); + if (typeGroups.Count == 1) { + foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) { + gGrid.Add((null, null, g.SortId, g.Min, g.Avg, g.Max, null)); + } + } else { + foreach (var t in typeGroups) { + gGrid.Add((null, t.Type == "R" ? "Rot" : "Weiß", null, t.Min, t.Avg, t.Max, t.Type)); + foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult && g.Type == t.Type).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) { + gGrid.Add((null, null, g.SortId, g.Min, g.Avg, g.Max, null)); + } + } } } if (attrGroups.Count == 1) { var g = attrGroups.First(); - var name = g.Attr == null && g.Cult == null ? null : g.Attr + (g.Attr != null && g.Cult != null ? " / " : "") + g.Cult; + var name = GetGroupName(g.Attr, g.Cult); if (name != null) { wText += $" [{name}]"; gText += $" [{name}]"; @@ -1094,40 +1144,43 @@ namespace Elwig.Services { } } else if (attrGroups.Count <= 4) { - wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; - gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; + wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (GetGroupName(g.Attr, g.Cult) is string s ? $" [{s}]" : "")))}"; + gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (GetGroupName(g.Attr, g.Cult) is string s ? $" [{s}]" : "")))}"; } } return (wText, wGrid.ToArray(), gText, gGrid.ToArray()); } - public static (Grid WeightGrid, Grid GradationGrid) GenerateToolTip((string?, string?, int, int?, int)[] weightData, (string?, string?, double, double, double)[] gradationData) { + public static (Grid WeightGrid, Grid GradationGrid) GenerateToolTip((string?, string?, string?, int, int?, int?, int, string?)[] weightData, (string?, string?, string?, double, double, double, string?)[] gradationData) { var wGrid = new Grid(); wGrid.ColumnDefinitions.Add(new() { Width = new(10) }); - wGrid.ColumnDefinitions.Add(new() { Width = new(60) }); + wGrid.ColumnDefinitions.Add(new() { Width = new(10) }); wGrid.ColumnDefinitions.Add(new() { Width = new(80) }); + wGrid.ColumnDefinitions.Add(new() { Width = new(80) }); + wGrid.ColumnDefinitions.Add(new() { Width = new(50) }); wGrid.ColumnDefinitions.Add(new() { Width = new(50) }); wGrid.ColumnDefinitions.Add(new() { Width = new(50) }); int rowNum = 0; foreach (var row in weightData) { - if (rowNum != 0 && row.Item2 == null) rowNum++; - AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5); + if (rowNum != 0 && row.Item2 == null && row.Item3 == null) rowNum++; + AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5, row.Item6, row.Item7, row.Item8); } var gGrid = new Grid(); gGrid.ColumnDefinitions.Add(new() { Width = new(10) }); - gGrid.ColumnDefinitions.Add(new() { Width = new(60) }); + gGrid.ColumnDefinitions.Add(new() { Width = new(10) }); + gGrid.ColumnDefinitions.Add(new() { Width = new(80) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); - gGrid.AddToolTipCell("Min.", 0, 2, alignCenter: true); - gGrid.AddToolTipCell("⌀", 0, 3, alignCenter: true); - gGrid.AddToolTipCell("Max.", 0, 4, alignCenter: true); + gGrid.AddToolTipCell("Min.", 0, 3, alignCenter: true); + gGrid.AddToolTipCell("⌀", 0, 4, alignCenter: true); + gGrid.AddToolTipCell("Max.", 0, 5, alignCenter: true); rowNum = 1; foreach (var row in gradationData) { - if (rowNum != 1 && row.Item2 == null) rowNum++; - AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5); + if (rowNum != 1 && row.Item2 == null && row.Item3 == null) rowNum++; + AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5, row.Item6, row.Item7); } return (wGrid, gGrid);