using System.Text.Json; using Admin.NET.Plugin.AiDOP.Dto.S8.Demo; using Admin.NET.Plugin.AiDOP.Entity.S8.Demo; namespace Admin.NET.Plugin.AiDOP.Service.S8.Demo; /// /// ORDER-FLOW-BE-DEMO-DATASET-RESET-1:订单执行档案 demo 只读服务。 /// 双口径:/orders 返回 20 单明细;/aggregate-snapshot 返回独立 105 单基线快照(非明细汇总)。 /// public class S8DemoOrderFlowService : ITransient { private readonly SqlSugarRepository _orderRep; private readonly SqlSugarRepository _stageRep; private readonly SqlSugarRepository _snapshotRep; public S8DemoOrderFlowService( SqlSugarRepository orderRep, SqlSugarRepository stageRep, SqlSugarRepository snapshotRep) { _orderRep = orderRep; _stageRep = stageRep; _snapshotRep = snapshotRep; } public async Task> ListOrdersAsync() { var orders = await _orderRep.AsQueryable() .OrderBy(x => x.SortNo) .ToListAsync(); if (orders.Count == 0) return new List(); var orderIds = orders.Select(o => o.Id).ToList(); var stages = await _stageRep.AsQueryable() .Where(s => orderIds.Contains(s.OrderId)) .OrderBy(s => s.OrderId).OrderBy(s => s.SortNo) .ToListAsync(); var stagesByOrder = stages.GroupBy(s => s.OrderId).ToDictionary(g => g.Key, g => g.ToList()); return orders.Select(o => MapOrder(o, stagesByOrder.TryGetValue(o.Id, out var ls) ? ls : new())).ToList(); } public async Task GetOrderAsync(string soNo) { var order = await _orderRep.AsQueryable().FirstAsync(x => x.SoNo == soNo); if (order == null) return null; var stages = await _stageRep.AsQueryable() .Where(s => s.OrderId == order.Id) .OrderBy(s => s.SortNo) .ToListAsync(); return MapOrder(order, stages); } public async Task GetAggregateSnapshotAsync() { var row = await _snapshotRep.AsQueryable() .Where(x => x.SnapshotCode == "CHAIN_AGGREGATE_BASELINE") .FirstAsync(); if (row == null) return null; return new AdoDemoOrderFlowSnapshotDto { SnapshotCode = row.SnapshotCode, SnapshotLabel = row.SnapshotLabel, TotalOrders = row.TotalOrders, TotalCustomers = row.TotalCustomers, AvgResponseMinutes = row.AvgResponseMinutes, AvgProcessingMinutes = row.AvgProcessingMinutes, AvgLossMinutes = row.AvgLossMinutes, StageSnapshots = ParseStageSnapshots(row.StageSnapshotsJson), Remark = row.Remark, }; } private static AdoDemoOrderFlowDto MapOrder(AdoDemoOrderFlow o, List stages) => new() { SoNo = o.SoNo, ProductName = o.ProductName, ProductLine = o.ProductLine, CustomerName = o.CustomerName, CustomerCode = o.CustomerCode, CustomerType = o.CustomerType, Region = o.Region, Priority = o.Priority, MaterialCode = o.MaterialCode, SupplierGroup = o.SupplierGroup, WorkflowStatus = o.WorkflowStatus, CurrentNodeKey = o.CurrentNodeKey, FocusNodeKey = o.FocusNodeKey, CurrentNodeLabel = o.CurrentNodeLabel, NodeStatus = o.NodeStatus, ReleaseAt = FormatDateTime(o.ReleaseAt), TargetCycleDays = o.TargetCycleDays, CurrentCycleDays = o.CurrentCycleDays, ActualCycleDays = o.ActualCycleDays, NodeVarianceDays = o.NodeVarianceDays, CumulativeVarianceDays = o.CumulativeVarianceDays, ExceptionCount = o.ExceptionCount, ResponseMinutes = o.ResponseMinutes, ProcessingMinutes = o.ProcessingMinutes, TotalLossMinutes = o.TotalLossMinutes, ExceptionStatus = o.ExceptionStatus, Lifecycle = stages.OrderBy(s => s.SortNo).Select(MapStage).ToList(), }; private static AdoDemoOrderFlowStageDto MapStage(AdoDemoOrderFlowStage s) => new() { StageKey = s.StageKey, StageName = s.StageName, SortNo = s.SortNo, PlannedDays = s.PlannedDays, ActualDays = s.ActualDays, ExpectedDate = s.ExpectedDate.ToString("yyyy-MM-dd"), ActualStartAt = s.ActualStartAt.HasValue ? FormatDateTime(s.ActualStartAt.Value) : null, ActualEndAt = s.ActualEndAt.HasValue ? FormatDateTime(s.ActualEndAt.Value) : null, Status = s.Status, NodeVarianceDays = s.NodeVarianceDays, CumulativeVarianceDays = s.CumulativeVarianceDays, }; private static string FormatDateTime(DateTime dt) => dt.ToString("yyyy-MM-dd HH:mm"); private static readonly JsonSerializerOptions JsonOpts = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true, }; private static List ParseStageSnapshots(string json) { if (string.IsNullOrWhiteSpace(json)) return new(); var items = JsonSerializer.Deserialize>(json, JsonOpts); return items ?? new(); } }