using System.Text; using System.Text.Json; namespace Admin.NET.Plugin.AiDOP.Order; /// /// 销售订单保存前后快照与差异文本(用于操作日志) /// internal static class SeOrderAuditHelper { private static readonly JsonSerializerOptions JsonOpt = new() { WriteIndented = false, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; public static string SnapshotOrderJson(SeOrder o) { var dict = OrderToFlat(o); return JsonSerializer.Serialize(dict, JsonOpt); } public static string SnapshotEntriesJson(IEnumerable entries) { var list = entries .OrderBy(e => e.EntrySeq ?? 0) .Select(EntryToFlat) .ToList(); return JsonSerializer.Serialize(list, JsonOpt); } public static string BuildCombinedSnapshotJson(SeOrder? order, List entries) { var root = new { header = order == null ? null : OrderToFlat(order), entries = entries.OrderBy(e => e.EntrySeq ?? 0).Select(EntryToFlat).ToList() }; return JsonSerializer.Serialize(root, JsonOpt); } /// 生成「变动前 / 变动后」可读文本 + 结构化 JSON public static (string Content, string? BeforeJson, string? AfterJson) BuildUpdateDiff( SeOrder beforeOrder, List beforeEntries, SeOrder afterOrder, List afterEntries) { var beforeCombined = BuildCombinedSnapshotJson(beforeOrder, beforeEntries); var afterCombined = BuildCombinedSnapshotJson(afterOrder, afterEntries); var sb = new StringBuilder(); sb.Append("修改订单,订单编号:").Append(afterOrder.BillNo ?? "—").Append('。').AppendLine(); var hBefore = OrderToFlat(beforeOrder); var hAfter = OrderToFlat(afterOrder); foreach (var key in hBefore.Keys.Union(hAfter.Keys)) { hBefore.TryGetValue(key, out var ov); hAfter.TryGetValue(key, out var nv); if (string.Equals(ov, nv, StringComparison.Ordinal)) continue; sb.Append(" 【").Append(key).Append("】变动前:「").Append(ov ?? "—").Append("」→ 变动后:「").Append(nv ?? "—").AppendLine("」"); } var beforeById = beforeEntries.ToDictionary(e => e.Id); var afterById = afterEntries.ToDictionary(e => e.Id); foreach (var id in beforeById.Keys.Union(afterById.Keys)) { beforeById.TryGetValue(id, out var eb); afterById.TryGetValue(id, out var ea); if (eb == null && ea != null) { sb.Append(" 【新增明细】行").Append(ea.EntrySeq).Append(" 物料:").AppendLine(ea.ItemNumber ?? "—"); continue; } if (eb != null && ea == null) { sb.Append(" 【删除明细】行").Append(eb.EntrySeq).Append(" 物料:").AppendLine(eb.ItemNumber ?? "—"); continue; } if (eb == null || ea == null) continue; var fb = EntryToFlat(eb); var fa = EntryToFlat(ea); var lineChanged = false; foreach (var key in fb.Keys.Union(fa.Keys)) { fb.TryGetValue(key, out var ov); fa.TryGetValue(key, out var nv); if (string.Equals(ov, nv, StringComparison.Ordinal)) continue; if (!lineChanged) { sb.Append(" 【明细行").Append(ea.EntrySeq).Append("】物料 ").Append(ea.ItemNumber ?? "—").AppendLine(); lineChanged = true; } sb.Append(" ").Append(key).Append(":变动前「").Append(ov ?? "—").Append("」→ 变动后「").Append(nv ?? "—").AppendLine("」"); } } var content = sb.ToString().TrimEnd(); if (content.IndexOf('→') < 0 && content.IndexOf("【新增明细】", StringComparison.Ordinal) < 0 && content.IndexOf("【删除明细】", StringComparison.Ordinal) < 0) content = "修改订单,订单编号:" + (afterOrder.BillNo ?? "—") + "。(主表与明细字段无变化)"; return (content, beforeCombined, afterCombined); } private static Dictionary OrderToFlat(SeOrder o) => new() { ["订单编号"] = o.BillNo, ["订单类型"] = o.OrderType switch { 1 => "销售", 2 => "计划", _ => o.OrderType?.ToString() }, ["客户编码"] = o.CustomNo, ["客户名称"] = o.CustomName, ["签订日期"] = o.Date?.ToString("yyyy-MM-dd"), ["客户级别"] = o.CustomLevel?.ToString(), ["加急"] = o.Urgent == 1 ? "加急" : "普通", ["客户订单号"] = o.BillFrom, ["国家"] = o.Country, ["客户下单日期"] = o.RDate?.ToString("yyyy-MM-dd"), ["流程状态"] = o.FlowState, }; private static Dictionary EntryToFlat(SeOrderEntry e) => new() { ["明细Id"] = e.Id.ToString(), ["行号"] = e.EntrySeq?.ToString(), ["物料编码"] = e.ItemNumber, ["物料名称"] = e.ItemName, ["规格"] = e.Specification, ["单位"] = e.Unit, ["数量"] = e.Qty?.ToString("0.######"), ["客户要求交期"] = e.PlanDate?.ToString("yyyy-MM-dd"), ["最终交货日期"] = e.Date?.ToString("yyyy-MM-dd"), ["系统建议交期"] = e.SysCapacityDate?.ToString("yyyy-MM-dd"), ["备注"] = e.Remark, ["进度"] = e.Progress switch { 0 => "再评审", 1 => "新建", 2 => "评审", 3 => "确认", _ => e.Progress?.ToString() }, ["交付数量"] = e.DeliverCount?.ToString("0.######"), }; }