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();
}
}