diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs index 7e4376cf..1a56a04e 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs @@ -14,7 +14,7 @@ public partial class TrackService private readonly ITrackTemplateRepository _trackTemplateRepository; /// - /// 查询轨迹 + /// 查询轨迹(时区补正) /// /// /// @@ -90,12 +90,17 @@ public partial class TrackService } // 排序 - var sortedList = await TracksOrdered(res, input); + var sortedList = await TracksOrdered(res, input, input.SortMethod, input.TrackTemplateCode); return new UnifyResultDto>(true, sortedList, "操作成功"); } + /// + /// 查询轨迹(原样返回) + /// + /// + /// [HttpPost("Track/QueryV2")] public async Task>> QueryV2Async(GetTrackInputV2 input) { @@ -163,15 +168,15 @@ public partial class TrackService } // 排序 - var sortedList = await TracksOrdered(res, input); + var sortedList = await TracksOrdered(res, input, input.SortMethod); return new UnifyResultDto>(true, sortedList, "操作成功"); } - private async Task> TracksOrdered(List list, GetTrackInput input) + private async Task> TracksOrdered(List list, OrderNosInfo orderNosInfo, SortMethod? sortMethod, string? trackTemplateCode = null) { - switch (input.SortMethod) + switch (sortMethod) { case SortMethod.ByTrackTime: case SortMethod.ByTemplateAndTrackTime: @@ -184,11 +189,11 @@ public partial class TrackService list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time))); break; default: - throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式"); + throw new ArgumentOutOfRangeException(nameof(sortMethod), sortMethod, "不支持的排序方式"); } - if (input.SortMethod != SortMethod.ByTemplateAndTrackTime - && input.SortMethod != SortMethod.ByTemplateAndTrackTimeDesc) + if (sortMethod != SortMethod.ByTemplateAndTrackTime + && sortMethod != SortMethod.ByTemplateAndTrackTimeDesc) { return list; } @@ -196,134 +201,178 @@ public partial class TrackService //查出订单模板 var templates = await _trackTemplateRepository.GetTrackTemplateListAsync(new GetTrackTemplateListInputVo { - SubSystemId = input.SubSystemId, - TemplateCode = input.TrackTemplateCode + SubSystemId = orderNosInfo.SubSystemId, + TemplateCode = trackTemplateCode }); if (templates.Count == 0) { - throw new BusinessException("轨迹模板不存在"); + return list; } + //查出订单和模板的关系,构建订单号和模板code的关系 + var orderNoTemplateDict = (await _orderRepository + .GetOrderTemplateAsync(orderNosInfo.SubSystemId, orderNosInfo.OrderType, orderNosInfo.OrderNos)) + .ToDictionary(x => x.OrderNo, x => x.TemplateCodes?.Split(",").ToHashSet()); + + //查询出订单和模板的关联关系,保证该订单使用自己的模板排序 foreach (var getTrackOutput in list) { - getTrackOutput.TrackDetails = SortByTemplate(getTrackOutput.TrackDetails, templates, input.SortMethod.Value); + //查看该订单具有的模板 + var curOrderNoTemplateCodes = orderNoTemplateDict[getTrackOutput.OrderNo]; + if (curOrderNoTemplateCodes == null || curOrderNoTemplateCodes.Count == 0) continue; + + //选出这个订单号所具有的模板 + var tipTemplates = templates.Where(x => curOrderNoTemplateCodes.Contains(x.TemplateCode)).ToList(); + if (tipTemplates.Count == 0) continue; + + getTrackOutput.TrackDetails = SortByTemplatesAsync(getTrackOutput.TrackDetails, tipTemplates, sortMethod == SortMethod.ByTemplateAndTrackTime); } return list; } - private async Task> TracksOrdered(List list, GetTrackInputV2 input) + /// + /// 轨迹发生时间(统一utc)排序,相同时间按模板排序,考虑多个模板的情况 + /// + /// + private static List SortByTemplatesAsync(List seq, List templates, bool isAsc = true) { - switch (input.SortMethod) + //转化为统一时间 + var trackWraps = seq.Select(x => new TrackWrap(x)); + var sortedTracks = (isAsc + ? trackWraps.OrderBy(x => x.Time) + : trackWraps.OrderByDescending(x => x.Time)).ToList(); + + + //用于统计时间相同的轨迹 + var timeEqTrackDict = new Dictionary>(); + for (var i = 0; i < sortedTracks.Count; i++) { - case SortMethod.ByTrackTime: - case SortMethod.ByTemplateAndTrackTime: - // tips:quick-sort 直接修改原list - list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time))); - break; - case null: - case SortMethod.ByTrackTimeDesc: - case SortMethod.ByTemplateAndTrackTimeDesc: - list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time))); - break; - default: - throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式"); - } - - return list; - } - - //按模板排序 - private static List SortByTemplate(List tracks, List templates, SortMethod sortMethod) - { - if (templates.Count == 0 || - tracks.Count == 0) - { - return new List(); - } - - var isAsc = sortMethod == SortMethod.ByTemplateAndTrackTime; - - var allTemplateCodes = new HashSet(); - - foreach (var template in templates) - { - tracks = Sort(tracks, template, isAsc, allTemplateCodes); - } - // tracks = templates.Aggregate(tracks, - // (current, template) => Sort(current, template, isAsc, allTemplateCodes)); - - return tracks; - } - - private static List Sort(List seq, TrackTemplateOutputVo template, bool isAsc = true, HashSet? allTemplateCodes = null) - { - if (template.TemplateContents.Count == 0) - { - return seq; - } - - // 创建一个字典,用于存储排序序列中元素的索引 - var sortDict = new Dictionary(); - template.TemplateContents.Sort((x, y) => x.Sort.CompareTo(y.Sort)); - var sortSeq = template.TemplateContents - .Select(x => seq.FirstOrDefault(y => y.Code == x.Code)) - .Where(x => x != null) - .ToList(); - for (var i = 0; i < sortSeq.Count; i++) - { - sortDict[sortSeq[i]!] = isAsc ? i : sortSeq.Count - i; - } - - // 将模板code添加到上下文集合中 - if (allTemplateCodes != null) - { - allTemplateCodes.UnionWith(template.TemplateContents.Select(x => x.Code)); - } - - // 根据排序序列和字典中的索引对序列进行排序 - // 使用稳定排序算法,如OrderBy,它保持相等元素的相对顺序 - var sorted = seq.OrderBy(item => sortDict.GetValueOrDefault(item, int.MaxValue)).ToList(); - - // 存在 - if (allTemplateCodes != null) - { - //查询到没有命中到模板的轨迹 - var noTipTemplateTracks = sorted.Where(x => !allTemplateCodes.Contains(x.Code)).ToList(); - - //查询未命中轨迹的索引字典 - var trackIdxDict = new Dictionary(); - var trackSortDict = new SortedDictionary(); - foreach (var track in noTipTemplateTracks) - { - trackIdxDict[track] = sorted.IndexOf(track); - trackSortDict[trackIdxDict[track]] = track; - } - - //没有命中的轨迹排序 - var noTipTemplateTrackSorted = (isAsc - ? noTipTemplateTracks.OrderBy(x => x.Time) - : noTipTemplateTracks.OrderByDescending(x => x.Time)) - .ToList(); - - for (var i = 0; i < trackSortDict.Count; i++) - { - //在序列中的实际位置 - var (idx, st) = trackSortDict.ElementAt(0); - //在这个位置它应该是哪个轨迹 - var track = noTipTemplateTrackSorted[0]; - //交换位置 - if (track != st) + var trackWrap = sortedTracks[i]; + if (timeEqTrackDict.TryGetValue(trackWrap.Time, out var list)) + list.Add(new TrackIdxWarp(trackWrap.Track, i)); + else + timeEqTrackDict.Add(trackWrap.Time, new List { - var idx2 = trackIdxDict[track]; - sorted[idx2] = st; - sorted[idx] = track; + new TrackIdxWarp(trackWrap.Track, i) + }); + } + + + //选出需要按模板重排序的轨迹 + var timeEqTracks = timeEqTrackDict + .Where(kv => kv.Value.Count > 1) + .ToDictionary(kv => kv.Key, kv => kv.Value); + + //初始化为最后一个模板排序 + var preSortDict = templates[templates.Count - 1] + .TemplateContents + .OrderBy(x => x.Sort) + .ToDictionary(x => x.Code, x => x.Sort); + + for (var i = templates.Count - 2; i >= 0; i--) + { + var curCodeSortDict = templates[i] + .TemplateContents + .ToDictionary(x => x.Code, y => y.Sort); + + //没在之前模板出现的code + var noTipPreCodeSortDict = curCodeSortDict + .Where(x => !preSortDict.ContainsKey(x.Key)) + .ToDictionary(x => x.Key, y => y.Value); + + //插入未命中的模板code + foreach (var (noTipCode, curNoTipCodeSort) in noTipPreCodeSortDict) + { + //初始化插入位置 + var insertPos = -1; + foreach (var (preCode, _) in preSortDict) + { + if (curCodeSortDict.TryGetValue(preCode, out var preCodeSort)) + { + //未命中的相对于之前模板的偏后,设置插入位置在 + if (preCodeSort < curNoTipCodeSort) + { + insertPos = preSortDict[preCode] + 1; + } + } + } + + //结束了还没选好位置,未命中的code相对于之前的模板code在当前模板最前面 + if (insertPos == -1) + { + foreach (var (c, s) in preSortDict) + preSortDict[c] = s + 1; + preSortDict[noTipCode] = 0; + } + else + { + foreach (var (c, s) in preSortDict.Where(x => x.Value >= insertPos)) + preSortDict[c] = s + 1; + preSortDict[noTipCode] = insertPos; } } } - return sorted; + + foreach (var trackIdxWarps in timeEqTracks.Values) + { + var curIndex = trackIdxWarps.Min(x => x.Index); + //按模板从小到大排序 + var sortByTemplate = (isAsc + ? trackIdxWarps + .OrderBy(x => preSortDict.GetValueOrDefault(x.Track.Code, int.MaxValue)) + : trackIdxWarps + .OrderByDescending(x => preSortDict.GetValueOrDefault(x.Track.Code, int.MaxValue)) + ).ToList(); + for (var j = 0; j < sortByTemplate.Count; j++) + { + var track = sortByTemplate[j]; + //当前索引不对应 + if (track.Index != curIndex + j) + { + var temp1 = sortedTracks[track.Index].Track; + var temp2 = sortedTracks[curIndex + j].Track; + sortedTracks[track.Index].Track = temp2; + sortedTracks[curIndex + j].Track = temp1; + trackIdxWarps.First(x => x.Index == curIndex + j).Index = track.Index; + track.Index = curIndex + j; + } + } + } + + return sortedTracks.Select(x => x.Track).ToList(); + } + + + private class TrackIdxWarp + { + public TrackDetail Track { get; set; } + public int Index { get; set; } + + public TrackIdxWarp(TrackDetail track, int index) + { + Track = track; + Index = index; + } + } + + + private class TrackWrap + { + public TrackDetail Track { get; set; } + + public DateTime Time { get; set; } + + public TrackWrap(TrackDetail track) + { + Track = track; + var timeZone = track.TimeZone ?? GlobalConst.NoneTrackTimeZone; + Time = Math.Abs(timeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? track.Time + : track.Time.Subtract(TimeSpan.FromHours(timeZone)); + } } } diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index f20c415e..eca70b47 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -30,6 +30,7 @@ public partial class TrackService : ApplicationService, ITrackService IHttpClientProxy requestCurrentUserService, ITrackTemplateRepository trackTemplateRepository) { _orderRepository = orderRepository; + this._orderRepository = orderRepository; _capPublisher = capPublisher; _trackContentRepository = trackContentRepository; _requestCurrentUserService = requestCurrentUserService; diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs index 96be07a4..467ab9c0 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs @@ -12,7 +12,7 @@ public interface IOrderRepository : IBasicRepository /// Task> GetTrackOrderPagedList(GetPageTrackOrderInputVO input); - /// + /// /// 通过三方平台和三方单号查询订单 /// /// 三方平台 @@ -62,6 +62,27 @@ public interface IOrderRepository : IBasicRepository /// Task> GetSubSystemListByCodesAsync(List codes); + #region 订单模板 + + /// + /// 根据订单id,获取订单所属的模板 + /// + /// + /// + Task> GetOrderTemplateAsync(int[] orderId); + + /// + /// 根据子系统+订单号+类型,获取订单所属的模板 + /// + /// + /// + /// + /// + Task> GetOrderTemplateAsync(int subSystemId,int orderType,List orderNos); + + #endregion + + #region 订单关联 /// diff --git a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs index efae67b2..e8a50f2d 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs @@ -45,6 +45,8 @@ public interface ITrackTemplateRepository : IBasicRepository> whereExpression); Task> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input); + Task> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input); + Task> GetContentByTemplateCodes(string[] codes, int systemId); } diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs new file mode 100644 index 00000000..26c110a0 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs @@ -0,0 +1,13 @@ +namespace SJZY.Track.Domain.Dtos.Order; + +/// +/// 订单关联的模板模型 +/// +public class OrderTemplateVO +{ + public int OrderId { get; set; } + + public string OrderNo { get; set; } + + public string? TemplateCodes { get; set; } +} diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index 90e6c5bf..a071f693 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Caching.Memory; using SJZY.Expand.ABP.Core.Logger; using SJZY.Track.Domain; using SJZY.Track.Domain.Aggregates.OrderAggregate; @@ -10,56 +11,64 @@ namespace SJZY.Track.Repository.Repositories; public class OrderRepository : BasicRepository, IOrderRepository, ITransientDependency { - public async Task> GetTrackOrderPagedList(GetPageTrackOrderInputVO input) + //MemoryCache本身线程安全简单使用,短暂数据不一致可以容忍,每过固定时间强制清除缓存 + private static readonly MemoryCache _memoryCache = new(new MemoryCacheOptions()); + private static readonly Dictionary _empty = new(); + private static readonly Dictionary> _empty2 = new(); + private const int ThirdPartyOrderNumberCacheTimeSpan = 3 * 60; + private const int MainDataEnumCacheTimeSpan = 5 * 60; + + private async Task> GetThirdPartyOrderNumberForCacheAsync(int[] orderIds) { - //查询完去重 - var pageList = await Context.Queryable() + const string key = "ThirdPartyOrderNumber"; + if (orderIds.Length == 0) return _empty; + + var dict = _memoryCache.Get>(key); + + orderIds = orderIds.Distinct().ToArray(); + if (dict != null && dict.Count != 0 && !orderIds.Except(dict.Keys).Any()) return dict; + + var orders = await Context.Queryable() .Includes(a => a.OrderPlatformNumbers) - .LeftJoin((a, b) => a.CustomId == b.Id && b.IsDeleted == false) - .LeftJoin((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false) - .LeftJoin((a, b, c, d) => a.Id == d.OrderId && d.IsDeleted == false) - .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) - .WhereIF(!input.OrderNos.IsNullOrEmpty(), (a, b, c, d) => input.OrderNos!.Contains(a.OrderNo) || input.OrderNos!.Contains(d.OrderNumber)) - .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, - (a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) - .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), - (a, b, c) => a.CreateTime >= input.CreateTimeStart) - .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, - (a, b, c) => a.CreateTime <= input.CreateTimeEnd) - .WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId) - .WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType) - .WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType) - .WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted) - .OrderByDescending((a, b, c) => a.CreateTime) - .Distinct() - .Select((a, b, c) => new TrackOrderVO + .LeftJoin((a, b) => a.Id == b.OrderId && b.IsDeleted == false) + .Where((a, b) => orderIds.Contains(a.Id)) + .Select(a => new OrderEntity() { Id = a.Id, - OrderNumber = a.OrderNo, - OrderType = a.OrderType, - QuestionType = a.QuestionType, - CustomerShortName = b.Abbreviation, - CustomerCode = b.Code, - CustomerId = a.CustomId, - NewestTrackContent = a.LatestTrackContent, - NewestTrackEnContent = a.LatestTrackEnContent, - NewestTrackPlace = a.LatestTrackPlace, - NewestTrackTime = a.LatestTrackTime, - IsFinish = a.IsCompleted, - CreateTime = a.CreateTime, - SubSystem = c.CnName, - SubSystemId = c.Id, - DestinationTimeZone = a.DestinationTimeZone, - EstimatedDeliveryDate = a.EstimatedDeliveryDate, - ThirdPartyOrderNumber = BuildThirdPartyOrderNumber(a.OrderPlatformNumbers) + OrderPlatformNumbers = a.OrderPlatformNumbers }) - .ToPagedListAsync(input.PageIndex, input.PageSize); + .ToListAsync(); + + if (orders.Count == 0) + return _empty; + + orders = orders.DistinctBy(x => x.Id).ToList(); + + dict = orders.ToDictionary(x => x.Id, x => BuildThirdPartyOrderNumber(x.OrderPlatformNumbers)); + + _memoryCache.Set(key, dict, new MemoryCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(ThirdPartyOrderNumberCacheTimeSpan), + Size = dict.Count + }); + return dict; + } + + private async Task>> GetMainDataEnumForCacheAsync(List orderTypes, List questTypes) + { + const string key = "EnumForMainData"; + if (orderTypes.Count == 0 && questTypes.Count == 0) return _empty2; + + var dict = _memoryCache.Get>>(key); + if (dict != null && dict.Count != 0 + && !orderTypes.Except(dict[GlobalConst.MainDataKey_OrderType].Keys).Any() + && !questTypes.Except(dict[GlobalConst.MainDataKey_TrackQuestionType].Keys).Any()) + { + return dict; + } - //查询订单类型描述 - var orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList(); - var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList(); //从主数据中心查询类型描述 - var typeDispDict = (await Context.Queryable() + dict = (await Context.Queryable() .Where(x => (x.Property == GlobalConst.MainDataKey_OrderType && orderTypes.Contains(x.Enumkey)) || (x.Property == GlobalConst.MainDataKey_TrackQuestionType && questTypes.Contains(x.Enumkey)) @@ -78,20 +87,161 @@ public class OrderRepository : BasicRepository, IOrderRepository, I y => y.ToDictionary(x => x.Enumkey, x => x.Disp) ); + if (dict.Count == 0) + return _empty2; + + _memoryCache.Set(key, dict, new MemoryCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(MainDataEnumCacheTimeSpan), + Size = dict.Count + }); + return dict; + } + + public async Task> GetTrackOrderPagedList(GetPageTrackOrderInputVO input) + { + //查询完去重 + UnifyPageResultDto pageList; + //没传递单号时 + if (input.OrderNos.IsNullOrEmpty()) + { + pageList = await Context.Queryable() + .LeftJoin((a, b) => a.CustomId == b.Id && b.IsDeleted == false) + .LeftJoin((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false) + .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) + .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), + (a, b, c) => a.CreateTime >= input.CreateTimeStart) + .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId) + .WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType) + .WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType) + .WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted) + .OrderByDescending((a, b, c) => a.CreateTime) + .Select((a, b, c) => new TrackOrderVO + { + Id = a.Id, + OrderNumber = a.OrderNo, + OrderType = a.OrderType, + QuestionType = a.QuestionType, + CustomerShortName = b.Abbreviation, + CustomerCode = b.Code, + CustomerId = a.CustomId, + NewestTrackContent = a.LatestTrackContent, + NewestTrackEnContent = a.LatestTrackEnContent, + NewestTrackPlace = a.LatestTrackPlace, + NewestTrackTime = a.LatestTrackTime, + IsFinish = a.IsCompleted, + CreateTime = a.CreateTime, + SubSystem = c.CnName, + SubSystemId = c.Id, + DestinationTimeZone = a.DestinationTimeZone, + EstimatedDeliveryDate = a.EstimatedDeliveryDate + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + //传递单号时 + else + { + var orderNos = input.OrderNos!.Distinct().ToList(); + + //匹配主单 + var orderIds = await Context.Queryable() + .Where(x => orderNos.Contains(x.OrderNo)) + .Select(x => x.Id) + .ToListAsync(); + + //匹配外部单 + var orderIdsForThirdParty = await Context.Queryable() + .Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber) && orderNos.Contains(x.OrderNumber)) + .Select(x => x.OrderId) + .ToListAsync(); + + var orderHashset = orderIds.ToHashSet(); + orderHashset.UnionWith(orderIdsForThirdParty); + orderIds = orderHashset.ToList(); + + //没有任何单 + if (orderIds.Count == 0) + { + return new UnifyPageResultDto + { + List = new List(), + Pagination = new PageInfoOutput() + { + PageIndex = input.PageIndex, + PageSize = input.PageSize, + Total = 0 + } + }; + } + + pageList = await Context.Queryable() + .Where(x => orderIds.Contains(x.Id)) + .LeftJoin((a, b) => a.CustomId == b.Id && b.IsDeleted == false) + .LeftJoin((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false) + .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) + .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), + (a, b, c) => a.CreateTime >= input.CreateTimeStart) + .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId) + .WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType) + .WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType) + .WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted) + .OrderByDescending((a, b, c) => a.CreateTime) + .Select((a, b, c) => new TrackOrderVO + { + Id = a.Id, + OrderNumber = a.OrderNo, + OrderType = a.OrderType, + QuestionType = a.QuestionType, + CustomerShortName = b.Abbreviation, + CustomerCode = b.Code, + CustomerId = a.CustomId, + NewestTrackContent = a.LatestTrackContent, + NewestTrackEnContent = a.LatestTrackEnContent, + NewestTrackPlace = a.LatestTrackPlace, + NewestTrackTime = a.LatestTrackTime, + IsFinish = a.IsCompleted, + CreateTime = a.CreateTime, + SubSystem = c.CnName, + SubSystemId = c.Id, + DestinationTimeZone = a.DestinationTimeZone, + EstimatedDeliveryDate = a.EstimatedDeliveryDate, + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + + + //补三方单号,从缓存中加速查 + var orderIdArr = pageList.List.Select(x => x.Id).ToArray(); + var thirdPartyOrderNumbers = await GetThirdPartyOrderNumberForCacheAsync(orderIdArr); + pageList.List.ForEach(x => x.ThirdPartyOrderNumber = thirdPartyOrderNumbers[x.Id]); + + //查询订单类型描述,从缓存中加速查 + var orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList(); + var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList(); + var typeDisplayDict = await GetMainDataEnumForCacheAsync(orderTypes, questTypes); + //填充数描述信息 pageList.List.ForEach(x => { - x.OrderTypeName = typeDispDict.TryGetValue(GlobalConst.MainDataKey_OrderType, out var orderTypeDisplayDict) + x.OrderTypeName = typeDisplayDict.TryGetValue(GlobalConst.MainDataKey_OrderType, out var orderTypeDisplayDict) ? orderTypeDisplayDict.TryGetValue(x.OrderType, out var orderTypeDisplay) ? orderTypeDisplay - : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]" - : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]"; + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] " + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] EnumKey:[{x.OrderType}]"; - x.QuestionTypeName = typeDispDict.TryGetValue(GlobalConst.MainDataKey_TrackQuestionType, out var questDisplayDict) + x.QuestionTypeName = typeDisplayDict.TryGetValue(GlobalConst.MainDataKey_TrackQuestionType, out var questDisplayDict) ? questDisplayDict.TryGetValue(x.QuestionType, out var questDisplay) ? questDisplay - : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]" - : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}]"; + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]" + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}] EnumKey:[{x.OrderType}]"; }); return pageList; @@ -246,6 +396,32 @@ public class OrderRepository : BasicRepository, IOrderRepository, I return res.Select(x => (x.Key, x.Id)).ToList(); } + public Task> GetOrderTemplateAsync(int[] orderId) + { + return Context.Queryable() + .Where(x => orderId.Contains(x.Id)) + .Select(a => new OrderTemplateVO + { + OrderId = a.Id, + OrderNo = a.OrderNo, + TemplateCodes = a.TemplateCodes + }) + .ToListAsync(); + } + + public Task> GetOrderTemplateAsync(int subSystemId, int orderType, List orderNos) + { + return Context.Queryable() + .Where(x => orderNos.Contains(x.OrderNo) && x.SubSystemId == subSystemId && x.OrderType == orderType) + .Select(a => new OrderTemplateVO + { + OrderId = a.Id, + OrderNo = a.OrderNo, + TemplateCodes = a.TemplateCodes + }) + .ToListAsync(); + } + public Task GetSystemInfoById(int id) { return Context.Queryable().FirstAsync(m => m.IsDeleted == false && m.Id == id); @@ -275,10 +451,12 @@ public class OrderRepository : BasicRepository, IOrderRepository, I /// private static string BuildThirdPartyOrderNumber(List orderPlatformNumberEntities) { + if (orderPlatformNumberEntities.Count == 0) return GlobalConst.EmptyString; const string separator = "、"; var thirdPartyOrderNumbers = orderPlatformNumberEntities .Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber)) - .Select(x => $"{x.OrderNumber}({x.Platform})").ToList(); + .Select(x => $"{x.OrderNumber}({x.Platform})") + .ToList(); return string.Join(separator, thirdPartyOrderNumbers); }