diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 9e403db8..8f843860 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -89,7 +89,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa } ); - // todo;预警计算 + // todo:预警计算 if (warningCalcOrders.Count > 0) WarningCalc_OrderDeletedOrCompleted(warningCalcOrders); } diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index a4e93ec2..a59cc7b9 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -198,7 +198,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(), @event.TrackCode); - // todo:引发预警计算 + // todo:引发预警计算 改MQ批量+分流 WarningCalc_AddedTrack(insertTracks); // 添加轨迹触发预警计算(异步) @@ -359,7 +359,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe // 批量写入操作日志 _ = _orderOperationRecordEsRepository.AddManyAsync(operationRecords); - // todo:引发预警计算 + // todo:引发预警计算 改MQ批量+分流 WarningCalc_UpdatedTrack(updateTracks); } diff --git a/src/SJZY.Track.Application/Hangfire/WarningNotifyAggregator.cs b/src/SJZY.Track.Application/Hangfire/WarningNotifyAggregator.cs index 48bc7beb..352430bf 100644 --- a/src/SJZY.Track.Application/Hangfire/WarningNotifyAggregator.cs +++ b/src/SJZY.Track.Application/Hangfire/WarningNotifyAggregator.cs @@ -45,7 +45,7 @@ public sealed class WarningNotifyAggregator : ITransientDependency // 4.绑定这个任务id(可能是多个)和jobId用户跟踪任务状态 public async Task<(List NotifyConfigs, HashSet taskIds)> ScanNotifyAndAggregateAsync() { - // 构建查询游标 todo:全量查询需要优化 + // 构建查询游标 todo:全量查询需要优化,直接存缓存? // var options = _optionsMonitor.CurrentValue; // var cursor = DateTime.Now.Subtract(TimeSpan.FromHours(options.ScanWarningNotifyTaskHourInterval)); diff --git a/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs b/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs index 83b59588..58274152 100644 --- a/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs +++ b/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs @@ -92,7 +92,7 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl // 同步更新订单主表 await TrackPushAfterUpdateOrderAsync(isAdd, @event.IsSuccess, logs); - // todo-test:引发预警计算 + // todo:引发预警计算 改MQ批量+分流 await _returnWarningHandler.ReceiveTrackPushRecordHandleAsync(@event.IsSuccess, @event.RequestParams, logs, pushInputs, updateInputs); // // 推送广播 diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index 6ce9a81d..f74c501e 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -67,7 +67,6 @@ public partial class TrackService : ApplicationService, ITrackService var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { - //TODO: log || ex throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs index 5b359c26..db1adefa 100644 --- a/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs +++ b/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs @@ -95,7 +95,7 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient // 查看缺失轨迹状态表达式是否有变化,如果有则更新 var trackStatusIds = trackStatusIdDict.Keys.ToHashSet(); - var expression = BuildMissingTrackStatusIdExpression(ruleItem, trackStatusIds); + var expression = ruleItem.BuildMissingTrackStatusIdExpression(trackStatusIds); if (!string.Equals(detail.MissingTrackStatusIds, expression)) { detail.MissingTrackStatusIds = expression; @@ -142,6 +142,7 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient // 3.以单的维度处理 // todo:优化流程减少N+1 var addDetails = new List(); + var updateDetails = new List(); var closeDetailsIds = new HashSet(); foreach (var order in orders) { @@ -169,9 +170,10 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient } if (hitRuleItems.Count == 0 && doneRuleItemIds.Count == 0) return; + var hitRuleItemDict = hitRuleItems.ToDictionary(x => x.Id); // 查出规则已经生成预警信息 - var hitRuleItemIds = hitRuleItems.Select(x => x.Id).ToHashSet(); + var hitRuleItemIds = hitRuleItemDict.Keys.ToHashSet(); var warningDetails = await _warningDetailsEsRepository.GetCompleteWarningDetailsAsync(new GetCompleteWarningDetailsVO { OrderIds = new HashSet(1) @@ -187,11 +189,16 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient // 已完结的预警规则,稍后修改明细状态为【已处理】 closeDetailsIds.UnionWith(warningDetails.Where(x => doneRuleItemIds.Contains(x.CompleteWarningRuleItemId)).Select(x => x.Id)); - // 排除已经生成预警信息的规则 - hitRuleItemIds.ExceptWith(warningDetails.Select(x => x.CompleteWarningRuleItemId)); + // 处理已存在的预警明细(命中规则的) + var existsWarningDetails = warningDetails.Where(x => hitRuleItemIds.Contains(x.CompleteWarningRuleItemId)).ToList(); + var needUpdateDetails = HandleExistsDetails(trackStatusIds, existsWarningDetails, hitRuleItemDict); + updateDetails.AddRange(needUpdateDetails); + + // 排除已经生成预警信息的规则 + hitRuleItemIds.ExceptWith(existsWarningDetails.Select(x => x.CompleteWarningRuleItemId)); - if (hitRuleItemIds.Count == 0) continue; // 生成预警明细 + if (hitRuleItemIds.Count == 0) continue; var needAddDetails = hitRuleItems .Where(x => hitRuleItemIds.Contains(x.Id)) .Select(x => BuildCompleteWarningDetails(order, trackStatusIds, x, rule.Version)); @@ -202,6 +209,9 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient // 4.预警由于不缺失轨迹变为失效,修改明细状态为【已处理】,并关闭相关预警通知任务 if (closeDetailsIds.Count > 0) await CloseWarningDetailLinksAsync(closeDetailsIds, CompleteWarningStatus.已处理); + // 更新预警明细 + if (updateDetails.Count > 0) + await _warningDetailsEsRepository.BulkUpdateCompleteWarningDetailsAsync(updateDetails); if (addDetails.Count == 0) return; @@ -213,6 +223,26 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient await _warningTaskRepository.BulkInsertWarningNotifyTaskAsync(notifyTasks); } + private static List HandleExistsDetails( + HashSet trackStatusIds, + List details, + Dictionary ruleItemDict + ) + { + var updateDetails = new List(); + foreach (var detail in details) + { + var ruleItem = ruleItemDict[detail.CompleteWarningRuleItemId]; // tips:一定存在 + var expression = ruleItem.BuildMissingTrackStatusIdExpression(trackStatusIds); + // 忽略状态表达式无变化的 + if (string.Equals(detail.MissingTrackStatusIds, expression)) continue; + detail.MissingTrackStatusIds = expression; + updateDetails.Add(detail); + } + + return updateDetails; + } + private static CompleteWarningDetailsIndex BuildCompleteWarningDetails(OrderEntity order, HashSet trackStatusIds, CompleteWarningRuleItemEntity ruleItem, string version) { return new CompleteWarningDetailsIndex() @@ -225,7 +255,7 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient // NotifyModes = ruleItem.NotifyModes, NotifyUsers = ruleItem.NotifyUsers, CheckPointTrackStatusId = ruleItem.CheckPointTrackStatusId, - MissingTrackStatusIds = BuildMissingTrackStatusIdExpression(ruleItem, trackStatusIds), + MissingTrackStatusIds = ruleItem.BuildMissingTrackStatusIdExpression(trackStatusIds), SubSystemId = order.SubSystemId, CustomId = order.CustomId, @@ -254,21 +284,6 @@ public sealed class CompleteWarningHandler : ICompleteWarningHandler, ITransient ).ToList(); } - // 根据规则和已有轨迹,构建缺失轨迹状态表达式 - private static string BuildMissingTrackStatusIdExpression(CompleteWarningRuleItemEntity ruleItem, HashSet trackStatusIds) - { - // 构建实际缺失的状态 - var missingGroups = new List>(); - foreach (var group in ruleItem.GetRequireTrackStatusIdGroups()) - { - if (group.Intersect(trackStatusIds).Any()) - continue; - missingGroups.Add(group); - } - - return string.Join(',', missingGroups.Select(sub => string.Join('/', sub))); - } - #endregion #region todo-test: 预警主体关闭 diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs index e44d1b99..17e635a0 100644 --- a/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs +++ b/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs @@ -403,6 +403,7 @@ public sealed class ReturnWarningHandler : IReturnWarningHandler, ITransientDepe #region todo-test: 预警信号批处理-修改或删除轨迹 + // todo:可以优化为直接通过轨迹的esId来寻找明细 public async Task TrackUpdatedOrDeletedHandleAsync(List updateOrDeleteSignals) { // 1.查询订单 @@ -435,7 +436,7 @@ public sealed class ReturnWarningHandler : IReturnWarningHandler, ITransientDepe // 2.获取预警明细,订单id+轨迹内容ids 默认关注(重试中,人工介入) var warningDetails = await _warningDetailsEsRepository.GetReturnWarningDetailsAsync(new GetReturnWarningDetailsVO { - OrderIdTrackContentIdsDict = orderIdTrackContentIdsDict + OrderIdTrackContentIdsDict = orderIdTrackContentIdsDict, }); if (warningDetails.Count == 0) return; diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs index 2ac10dc5..d7620ffa 100644 --- a/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs +++ b/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs @@ -441,7 +441,6 @@ public class TransportWarningHandler : ITransportWarningHandler, ITransientDepen // 命中规则 if (ruleItem.CanHitRule(trackStatusIds)) { - // todo: 出现一个订单,一个规则,多个任务? var task = ruleIdTasksDict.GetValueOrDefault(ruleId)?.FirstOrDefault(); var earliestTrack = trackStatusIdEarliestTrackDict[ruleItem.StartTrackStatusId]; diff --git a/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs b/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs index 8412465b..da5c51b9 100644 --- a/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs +++ b/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs @@ -82,19 +82,17 @@ public class ReturnWarningService : ApplicationService return new UnifyResultDto>(true, map.ToList()); - // todo:拆解优化 List BuildTrackStatus(string statusIds) { - return statusIds.Split(',') - .Select(x => + return statusIds.Split(',').Select(x => + { + var id = int.Parse(x); + return new TrackStatusDto { - var id = int.Parse(x); - return new TrackStatusDto - { - TrackStatus = trackStatusDict.GetValueOrDefault(id, GlobalConst.EmptyString), - TrackStatusId = id - }; - }).ToList(); + TrackStatus = trackStatusDict.GetValueOrDefault(id, GlobalConst.EmptyString), + TrackStatusId = id + }; + }).ToList(); } } @@ -115,6 +113,7 @@ public class ReturnWarningService : ApplicationService result.Pagination.PageSize, result.Pagination.Total); } + // todo:缓存优化 // 订单类型 var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync(); diff --git a/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs b/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs index 684c13cc..d179707a 100644 --- a/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs +++ b/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs @@ -64,7 +64,7 @@ public class TransportWarningService : ApplicationService .Select(x => x!.Value) .ToHashSet(); - // todo:加缓存 + // todo:缓存优化 Dictionary? areaNameDict = null; if (areaIds.Count > 0) { diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs index bf529ce9..af634e8f 100644 --- a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs +++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs @@ -15,7 +15,7 @@ public sealed class CompleteWarningDetailsIndex : IdBaseIndex //public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2 public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}] public int CheckPointTrackStatusId { get; set; } // (冗余)检查点轨迹状态Id - public string MissingTrackStatusIds { get; set; } //(冗余)缺失的轨迹状态 + public string MissingTrackStatusIds { get; set; } //(冗余)缺失的轨迹状态表达式 //订单信息 public int SubSystemId { get; set; } //(冗余)子系统Id diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs index d42877c3..c3880646 100644 --- a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs @@ -101,4 +101,20 @@ public sealed class CompleteWarningRuleItemEntity : IFullAuditedBasicEntitys, IE return false; } + + // 构建缺失轨迹状态表达式 + // 根据规则和已有轨迹,构建缺失轨迹状态表达式 + public string BuildMissingTrackStatusIdExpression(HashSet trackStatusIds) + { + // 构建实际缺失的状态 + var missingGroups = new List>(); + foreach (var group in GetRequireTrackStatusIdGroups()) + { + if (group.Intersect(trackStatusIds).Any()) + continue; + missingGroups.Add(group); + } + + return string.Join(',', missingGroups.Select(sub => string.Join('/', sub))); + } } diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs index 5b23f892..2c1029f7 100644 --- a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs +++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs @@ -87,7 +87,7 @@ public class ReturnWarningDetailsIndex : IdBaseIndex return false; } - // 匹配硅胶字段 + // 匹配比较字段,todo:考虑直接使用TrackEsId来匹配 public bool MatchExtra(string? compareFields, string? extra) { // 匹配字段为空,明细明细字段为空 diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs index d5ae6fdb..6ff141b9 100644 --- a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs +++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs @@ -147,8 +147,7 @@ public sealed class TransportWarningDetailsIndex : IdBaseIndex } // 预警规则描述,创建预警明细,更新场景(需要重新匹配),更新规则项目(需要重新匹配),更新规则区域名称 - // todo:缺失更新规则区域名称目前不被感知,出现预警明细和对于的规则区域名称不一致 - // todo:转化为bo的使用 + // todo:如果更新了规则区域名称不会同步到预警明细的描述中,出现预警明细和对于的规则区域名称不一致,考虑规则存缓存动态生成预警描述 public string GetWarningRuleDescription(TransportWarningSceneEntity scene, TransportWarningSceneRuleItemEntity ruleItem, RuleAreaEntity? ruleArea) { var res = new StringBuilder("{"); diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs index 436ae111..90a530b1 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs @@ -22,7 +22,7 @@ public partial class GlobalConst /// public const string OrderOperationRecordIndex = "sjzy_track_order_operation_records"; - // todo:以下为新增需要配置索引模板 + // todo:以下为新增需要配置索引模板(uat/prod) /// /// 运输时效预警明细 es索引名称(模板按天) /// diff --git a/src/SJZY.Track.Domain/Dtos/Warning/GetReturnWarningDetailsVO.cs b/src/SJZY.Track.Domain/Dtos/Warning/GetReturnWarningDetailsVO.cs index 71243a9e..795cfaa6 100644 --- a/src/SJZY.Track.Domain/Dtos/Warning/GetReturnWarningDetailsVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Warning/GetReturnWarningDetailsVO.cs @@ -19,10 +19,6 @@ public class GetReturnWarningDetailsVO public HashSet Status { get; set; } = DefaultFollowStatus; public Dictionary>? OrderIdTrackContentIdsDict { get; set; } - // todo:暂时用不到 - public Dictionary>? OrderIdTrackEsIdsDict { get; set; } - public HashSet<(int SubSystemId, int CustomId, int TrackContentId)>? PushConfigLinks { get; set; } - public bool HasDetailsIds => DetailsIds?.Count > 0; public bool HasRuleItemIds => RuleItemIds?.Count > 0; public bool HasWarningIds => WarningIds?.Count > 0; @@ -30,6 +26,4 @@ public class GetReturnWarningDetailsVO public bool HasTrackEsIds => TrackEsIds?.Count > 0; public bool HasPushContentConfigIds => PushContentConfigIds?.Count > 0; public bool HasOrderIdTrackContentIdsDict => OrderIdTrackContentIdsDict?.Count > 0; - public bool HasOrderIdTrackEsIdsDict => OrderIdTrackEsIdsDict?.Count > 0; - public bool HasPushConfigLinks => PushConfigLinks?.Count > 0; } diff --git a/src/SJZY.Track.Repository/Repositories/WarningDetailsEsRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningDetailsEsRepository.cs index e69d2556..ef1de94e 100644 --- a/src/SJZY.Track.Repository/Repositories/WarningDetailsEsRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/WarningDetailsEsRepository.cs @@ -373,33 +373,6 @@ public class WarningDetailsEsRepository : IWarningDetailsEsRepository, ITransien { musts.Add(c => c.Terms(f => f.Field(d => d.TrackEsId.Suffix("keyword")).Terms(input.TrackEsIds))); } - else if (input.HasOrderIdTrackEsIdsDict) - { - foreach (var (orderId, trackEsIds) in input.OrderIdTrackEsIdsDict!) - { - musts.Add(c => c.Bool(b => b.Must - ( - mu => mu.Term(f => f.OrderId, orderId), - mu => mu.Terms(t => t.Field(f => f.TrackEsId.Suffix("keyword")).Terms(trackEsIds)) - ))); - } - - isShouldQuery = true; - } - else if (input.HasPushConfigLinks) - { - foreach (var (subSystemId, customId, trackContentId) in input.PushConfigLinks!) - { - musts.Add(c => c.Bool(b => b.Must - ( - mu => mu.Term(f => f.SubSystemId, subSystemId), - mu => mu.Term(f => f.CustomId, customId), - mu => mu.Term(f => f.TrackContentId, trackContentId) - ))); - } - - isShouldQuery = true; - } else if (input.HasOrderIdTrackContentIdsDict) { foreach (var (orderId, trackContentIds) in input.OrderIdTrackContentIdsDict!)