using System.Globalization; using YY.Admin.Core.Entity; namespace YY.Admin.Core.Util; /// /// 「已入场重量」桌面端本地累计计算器。 /// 与后端 IMesXslRawMaterialEntryService.sumEnteredWeightByBillNos 保持同一口径: /// ① 把 totalPortions / portionWeight 按 "x/y/z/" 拆分 /// ② 逐位 (份数 × 每份重量) 累加,得到该 entry 的小计 /// ③ 同一榜单(BillNo)下所有 entry 的小计再次累加 /// 任一位置解析失败或缺失:静默跳过,保证 UI 降级可用。 /// public static class EnteredWeightCalculator { /// 累计一条入场记录的小计。 public static double SumOneEntry(string? totalPortions, string? portionWeight) { var portions = SplitJoined(totalPortions); var weights = SplitJoined(portionWeight); if (portions.Length == 0 || weights.Length == 0) { return 0d; } var n = Math.Min(portions.Length, weights.Length); double sum = 0d; for (var i = 0; i < n; i++) { if (!TryParse(portions[i], out var p) || !TryParse(weights[i], out var w)) { continue; } sum += p * w; } return sum; } /// 按 BillNo 分组累计「已入场重量」。返回 Dictionary<BillNo, 总和>。 public static Dictionary SumByBillNos( IEnumerable entries, IEnumerable billNos) { var keys = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var b in billNos) { if (!string.IsNullOrWhiteSpace(b)) keys.Add(b!); } var result = new Dictionary(StringComparer.OrdinalIgnoreCase); if (keys.Count == 0) { return result; } foreach (var e in entries) { if (string.IsNullOrWhiteSpace(e.BillNo) || !keys.Contains(e.BillNo!)) { continue; } var sub = SumOneEntry(e.TotalPortions, e.PortionWeight); if (sub == 0d) { continue; } if (result.TryGetValue(e.BillNo!, out var acc)) { result[e.BillNo!] = acc + sub; } else { result[e.BillNo!] = sub; } } return result; } private static string[] SplitJoined(string? value) { // 兼容 "x/y/z" 与 "x/y/z/" 两种格式;过滤空段 if (string.IsNullOrWhiteSpace(value)) { return Array.Empty(); } return value.Split('/') .Select(s => s.Trim()) .Where(s => s.Length > 0) .ToArray(); } private static bool TryParse(string s, out double v) => double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out v); }