feat:优化预警仓储逻辑

This commit is contained in:
hardstylewyl 2025-03-10 18:06:43 +08:00
parent e056585fc6
commit 99037a2da7
21 changed files with 157 additions and 83 deletions

View File

@ -37,15 +37,26 @@ public class TrackPushContentConfigDto
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 推送顺序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 轨迹内容id
/// 我们系统的轨迹内容id
/// </summary>
public int TrackContentId { get; set; }
/// <summary>
/// 我们系统的轨迹code
/// </summary>
public string TrackCode { get; set; } = null!;
/// <summary>
/// 推送顺序
/// 可交换顺序的轨迹内容id
/// </summary>
public int Sort { get; set; }
public int? SwapTrackContentId { get; set; }
/// <summary>
/// 可交换顺序的轨迹code

View File

@ -4,7 +4,6 @@ public class TrackPushInput
{
public string OrderNo { get; set; } = null!;
//原TrackItem,为了扩展字段入参变更为字典
public List<Dictionary<string,object?>> Data { get; set; } = new();
public string Log { get; set; }
@ -14,7 +13,6 @@ public class TrackUpdateInput
{
public string OrderNo { get; set; } = null!;
//原TrackItem,为了扩展字段入参变更为字典
public List<Dictionary<string,object?>> Data { get; set; } = new();
public string Log { get; set; }

View File

@ -1,5 +1,9 @@
namespace SJZY.Track.Application.Contract.Events;
/// <summary>
/// 轨迹推送事件
/// 每次可传递多个订单,但仅能传递同一个轨迹内容
/// </summary>
public class TrackPushEvent
{
/// <summary>
@ -55,11 +59,21 @@ public class TrackPushEvent
public struct SystemPushStruct
{
/// <summary>
/// 轨迹状态id
/// </summary>
public int TrackStatusId { get; set; }
/// <summary>
/// 轨迹状态
/// </summary>
public string TrackStatus { get; set; }
/// <summary>
/// 轨迹内容id
/// </summary>
public int TrackContentId { get; set; }
/// <summary>
/// 轨迹内容
/// </summary>

View File

@ -1,12 +1,10 @@
using System.Collections.Immutable;
using System.Text.Json;
using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Helpers;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Enums;

View File

@ -179,20 +179,15 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
return;
}
// //配置的类型如何和订单类型不一致则不允许推送
// if (config.OrderType != order.OrderType)
// {
// TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event,
// order);
// continue;
// }
var log = new TrackPushRecordIndex
{
OptionType = @event.OptionType.ToString(),
OrderId = order.Id,
OrderNo = order.OrderNo,
CompareFields = @event.SystemPushInfo.CompareFields,
TrackStatusId = @event.SystemPushInfo.TrackStatusId,
TrackStatus = @event.SystemPushInfo.TrackStatus,
TrackContentId = @event.SystemPushInfo.TrackContentId,
TrackCode = @event.TrackCode,
TrackContent = @event.SystemPushInfo.TrackContent,
TrackPlace = @event.SystemPushInfo.TrackPlace,
@ -255,21 +250,16 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
continue;
}
// // 配置的类型如何和订单类型不一致则不允许推送
// if (config.OrderType != order.OrderType)
// {
// TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event,
// order);
// continue;
// }
var log = new TrackPushRecordIndex
{
OptionType = @event.OptionType.ToString(),
OrderId = order.Id,
OrderNo = order.OrderNo,
CompareFields = @event.SystemPushInfo.CompareFields,
TrackStatusId = @event.SystemPushInfo.TrackStatusId,
TrackStatus = @event.SystemPushInfo.TrackStatus,
TrackCode = @event.TrackCode,
TrackContentId = @event.SystemPushInfo.TrackContentId,
TrackContent = @event.SystemPushInfo.TrackContent,
TrackPlace = @event.SystemPushInfo.TrackPlace,
TrackTime = @event.SystemPushInfo.TrackTime,
@ -308,21 +298,16 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
continue;
}
// //配置的类型如何和订单类型不一致则不允许推送
// if (config.OrderType != order.OrderType)
// {
// TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event,
// order);
// continue;
// }
var log = new TrackPushRecordIndex
{
OptionType = @event.OptionType.ToString(),
OrderId = order.Id,
OrderNo = order.OrderNo,
CompareFields = @event.SystemPushInfo.CompareFields,
TrackStatusId = @event.SystemPushInfo.TrackStatusId,
TrackStatus = @event.SystemPushInfo.TrackStatus,
TrackCode = @event.TrackCode,
TrackContentId = @event.SystemPushInfo.TrackContentId,
TrackContent = @event.SystemPushInfo.TrackContent,
TrackPlace = @event.SystemPushInfo.TrackPlace,
TrackTime = @event.SystemPushInfo.TrackTime,

View File

@ -178,12 +178,11 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
await _trackDetailsEsRepository.AddManyAsync(insertTracks);
//批量写入订单操作日志
_ = _orderOperationRecordEsRepository
.AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier
{
OrderNo = t.OrderNo,
OrderId = t.OrderId
})).ToList());
_ = _orderOperationRecordEsRepository.AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier
{
OrderNo = t.OrderNo,
OrderId = t.OrderId
})).ToList());
// 添加轨迹触发订单拉取状态更新
await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(),
@ -217,6 +216,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
});
// 触发轨迹推送事件(异步)
// tips:同一个轨迹内容,多个订单多条轨迹
var trackPushEvent = new TrackPushEvent
{
OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改,
@ -227,7 +227,9 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackCode = @event.TrackCode,
SystemPushInfo = new SystemPushStruct
{
TrackStatusId = trackContent.TrackStatusId,
TrackStatus = trackContent.TrackStatus,
TrackContentId = trackContent.TrackContentId,
TrackContent = trackContent.TrackContent,
TrackPlace = @event.TrackPlace,
TrackTime = @event.NewTrackTime ?? @event.TrackTime,

View File

@ -61,13 +61,13 @@ public class TrackPushService : ApplicationService, ITrackPushService
var subSystemCode = await _provideQueries.SubSystemId2CodeAsync(input.SubSystemId);
var orders = await _orderRepository.GetArrayAsync(x =>
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType &&
input.OrderNos.Contains(x.OrderNo),
x => new
{
x.Id,
x.CustomId
});
x.SubSystemId == input.SubSystemId
&& x.OrderType == input.OrderType
&& input.OrderNos.Contains(x.OrderNo), x => new
{
x.Id,
x.CustomId
});
if (!orders.Any())
{
@ -82,13 +82,11 @@ public class TrackPushService : ApplicationService, ITrackPushService
var name = userInfo.Data.UserName;
//查出需要推送的轨迹
var tracks = await _trackDetailsEsRepository
.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos,
new List<string>
{
input.TrackCode
});
//查出可能需要推送的轨迹
var tracks = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos, new List<string>
{
input.TrackCode
});
if (tracks.Count == 0)
{
throw new BusinessException(message: "没有需要推送的轨迹");
@ -116,13 +114,20 @@ public class TrackPushService : ApplicationService, ITrackPushService
}).ToList();
}
//不同单可能会有不同的轨迹内容,先推送只推送最新的一条
// 经过过滤后不存在需要推送的轨迹
if (tracks.Count == 0)
{
throw new BusinessException(message: "没有需要推送的轨迹");
}
// 构建每个单最早的轨迹(已经指定了code)
var orderIdTrackDict = tracks.GroupBy(x => x.OrderId)
.ToDictionary(x => x.Key, y => y.OrderByDescending(a => a.CreateTime).First());
//不同单可能会有不同的轨迹内容,手动推送只推送最新的一条
foreach (var order in orders)
{
//找出每个单的某个code的最新轨迹内容
var track = tracks.Where(x => x.OrderId == order.Id)
.OrderByDescending(x => x.CreateTime)
.FirstOrDefault();
var track = orderIdTrackDict.GetValueOrDefault(order.Id);
if (track == null) continue;
var trackPushEvent = new TrackPushEvent
@ -134,9 +139,11 @@ public class TrackPushService : ApplicationService, ITrackPushService
OrderIds = new[] { order.Id },
TrackCode = input.TrackCode,
OperationMan = name,
SystemPushInfo = new SystemPushStruct()
SystemPushInfo = new SystemPushStruct
{
TrackStatusId = track.TrackStatusId,
TrackStatus = track.TrackStatus,
TrackContentId = track.TrackContentId,
TrackContent = track.TrackContent,
TrackPlace = track.TrackPlace,
TrackTime = track.TrackTime,
@ -149,7 +156,7 @@ public class TrackPushService : ApplicationService, ITrackPushService
await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent);
}
return new UnifyResultDto(true, $"即将推送轨迹代码{input.TrackCode}给{orders.Length}个订单");
return new UnifyResultDto(true, $"即将推送轨迹代码{input.TrackCode}给{orderIdTrackDict.Count}个订单");
}
@ -180,8 +187,11 @@ public class TrackPushService : ApplicationService, ITrackPushService
public async Task<UnifyResultDto<List<TrackPushRecordOutput>>> GetTrackPushRecordsAsync([FromQuery] OrderNoInfo input)
{
var orderId = await _orderRepository.GetFirstAsync(x =>
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && input.OrderNo == x.OrderNo,
x => x.Id);
x.SubSystemId == input.SubSystemId
&& x.OrderType == input.OrderType
&& input.OrderNo == x.OrderNo,
x => x.Id
);
if (orderId == default)
{
throw new BusinessException(message: "订单不存在");
@ -192,6 +202,4 @@ public class TrackPushService : ApplicationService, ITrackPushService
var res = ObjectMapper.Map<List<TrackPushRecordIndex>, List<TrackPushRecordOutput>>(records);
return new UnifyResultDto<List<TrackPushRecordOutput>>(true, res, "操作成功");
}
}

View File

@ -84,8 +84,10 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
TimezoneFormat = trackPushConfig.TimezoneFormat,
ServiceProviderCode = item.ServiceProviderCode,
OrderType = item.OrderType,
TrackCode = item.TrackCode,
Sort = item.Sort,
TrackContentId = item.TrackContentId,
TrackCode = item.TrackCode,
SwapTrackContentId = item.SwapTrackContentId,
SwapTrackCode = item.SwapTrackCode,
TrackStatusValue = item.TrackStatusValue,
TrackContentCodeValue = item.TrackContentCodeValue,

View File

@ -3,8 +3,8 @@ using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Complete;
using SJZY.Track.Application.Contract.Dtos.Warning.Return;
using SJZY.Track.Application.Helpers;
using SJZY.Track.Application.Services.Warning.Handlers.Model;
using SJZY.Track.Application.Services.Warning.Handlers.Warning;
using SJZY.Track.Application.Services.Warning.Handlers;
using SJZY.Track.Application.Services.Warning.Model;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
@ -138,8 +138,7 @@ public class CompleteWarningService : ApplicationService
// 查最新轨迹
var orderIds = result.List.Select(x => x.OrderId).ToHashSet();
var orderTracks = await _trackDetailsEsRepository.GetLatestListAsync(orderIds);
var orderIdTrackDict = orderTracks.ToDictionary(x => x.OrderId);
var orderIdTrackDict = await _trackDetailsEsRepository.GetLatestDictAsync(orderIds);
// :填充子系统名称(冗余?)
// :填充客户简称(冗余?)
@ -207,14 +206,12 @@ public class CompleteWarningService : ApplicationService
TrackStatusId = id,
TrackStatus = trackStatusName
};
}).Where(x => x != null);
return trackStatus.ToList()!;
}
}
/// <summary>
/// 编辑完整预警规则列表
/// </summary>

View File

@ -70,7 +70,7 @@ public class TransportWarningService : ApplicationService
sb.Append($"{entity.CargoType}");
// 月份
if (!string.IsNullOrWhiteSpace(entity.Months))
sb.Append($"/{entity.Months.Replace("/", "|")}月份");
sb.Append($"/{entity.Months.Replace("/", ",")}月份");
// 中转
if (entity.IsTransit != null)
sb.Append($"/中转为{(entity.IsTransit.Value ? "是" : "否")}");

View File

@ -65,4 +65,10 @@ public interface IKpiAreaRepository : IBasicRepository<RuleAreaEntity>
/// </summary>
/// <returns></returns>
List<KpiAreaInfo>? GetAreaInfosByAreaId(int areaId);
/// <summary>
/// 获取所有区域信息
/// </summary>
/// <returns></returns>
Task<Dictionary<int, List<KpiAreaInfo>>> GetAreaInfosDictByAreaId(HashSet<int> areaIds);
}

View File

@ -1,5 +1,5 @@
using SJZY.Expand.ElasticSearch.Services;
using SJZY.Track.Domain.Dtos.TrackContents;
using SJZY.Track.Domain.Dtos.TrackDetails;
using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
@ -8,7 +8,14 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
{
Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode, bool forUpsert = false);
Task<List<TrackDetailsIndex>> GetLatestListAsync(HashSet<int> eventOrderIds);
// 复杂查询,返回 k:订单id v:轨迹列表
Task<Dictionary<int, List<TrackDetailsIndex>>> GetOrderTracksDictAsync(GetOrderTracksDictVO input);
// 查询订单的每个轨迹状态的最旧/早轨迹,返回 k:订单id v:[k:轨迹状态id,v:最早轨迹]
Task<Dictionary<int, Dictionary<int, TrackDetailsIndex>>> GetTrackStatusEarliestDictAsync(HashSet<int> orderIds);
// 查询订单的最新/晚轨迹,返回 k:订单id v:最早轨迹
Task<Dictionary<int, TrackDetailsIndex>> GetLatestDictAsync(HashSet<int> orderIds);
Task<List<TrackDetailsIndex>> GetLatestListAsync(int[] eventOrderIds, List<string> trackCodes);

View File

@ -5,5 +5,9 @@ namespace SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
public interface ITrackStatusRepository : IBasicRepository<TrackStatusEntity>
{
Task<GetTrackStatusDetailVO?> GetDetailAsync(int id);
Task<UnifyPageResultDto<GetTrackStatusListVO>> GetPageTrackStatus(GetPagedTrackStatusVO input);
// 获取轨迹状态Id与名称字典
Task<Dictionary<int, string>> GetTrackStatusIdNameDictAsync(HashSet<int> trackStatusIds);
}

View File

@ -12,8 +12,8 @@ public interface IWarningDetailsEsRepository
// 分页获取运输预警明细
Task<UnifyPageResultDto<TransportWarningDetailsIndex>> GetPageTransportWarningDetailsAsync(GetPageTransportWarningDetailsInputVO input);
// 获取运输预警明细(预警规则id+状态)
Task<List<TransportWarningDetailsIndex>> GetTransportWarningDetailsAsync(HashSet<int> ruleItemIds, HashSet<int> status);
// 复杂查询,只关注默认只关注(即将超时/已超时)
Task<List<TransportWarningDetailsIndex>> GetTransportWarningDetailsAsync(GetTransportWarningDetailsVO input);
// 更新运输预警明细
Task UpdateTransportWarningDetailsAsync(TransportWarningDetailsIndex detail);
@ -22,9 +22,7 @@ public interface IWarningDetailsEsRepository
Task BulkUpdateTransportWarningDetailsAsync(List<TransportWarningDetailsIndex> details, int maxRetries = 3);
// 批量关闭运输预警明细
Task BulkCloseTransportWarningDetailsAsync(HashSet<string> detailIds, int maxRetries = 3);
// 批量关闭运输预警明细
Task BulkCloseTransportWarningDetailsAsync(HashSet<int> ruleItemIds, int maxRetries = 3);
Task BulkCloseTransportWarningDetailsAsync(BulkCloseTransportWarningDetailsVO input, int maxRetries = 3);
// 新增运输预警明细
Task InsertTransportWarningDetailsAsync(TransportWarningDetailsIndex detail);
@ -39,6 +37,9 @@ public interface IWarningDetailsEsRepository
// 分页获取回传预警明细
Task<UnifyPageResultDto<ReturnWarningDetailsIndex>> GetPageReturnWarningDetailsAsync(GetPageReturnWarningDetailsInputVO input);
// 复杂查询,只关注默认只关注(重试中/人工介入)
Task<List<ReturnWarningDetailsIndex>> GetReturnWarningDetailsAsync(GetReturnWarningDetailsVO input);
// 获取回传日志列表
Task<List<ReturnMessageRecordIndex>> GetReturnMessageRecordListByIdAsync(string esId);
@ -48,6 +49,9 @@ public interface IWarningDetailsEsRepository
// 批量更新回传预警明细
Task BulkUpdateReturnWarningDetailsAsync(List<ReturnWarningDetailsIndex> details, int maxRetries = 3);
// 批量关闭回传预警明细
Task BulkCloseReturnWarningDetailsAsync(BulkCloseReturnWarningDetailsVO input, int maxRetries = 3);
// 新增回传预警明细
Task InsertReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail);
@ -67,6 +71,12 @@ public interface IWarningDetailsEsRepository
// 分页获取完整预警明细
Task<UnifyPageResultDto<CompleteWarningDetailsIndex>> GetPageCompleteWarningDetailsAsync(GetPageCompleteWarningDetailsInputVO input);
// 复杂查询,只关注默认只关注(待处理)
Task<List<CompleteWarningDetailsIndex>> GetCompleteWarningDetailsAsync(GetCompleteWarningDetailsVO input);
// 批量关闭完整预警明细
Task BulkCloseCompleteWarningDetailsAsync(BulkCloseCompleteWarningDetailsVO input, int maxRetries = 3);
// 更新完整预警明细
Task UpdateCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail);

View File

@ -19,7 +19,7 @@ public interface IWarningTaskRepository
// 批量添加预警通知任务
Task<int> BulkInsertWarningNotifyTaskAsync(List<WarningNotifyTaskEntity> entities);
// 关闭预警通知任务
// 关闭预警通知任务,预警类型+detailsId 可以唯一确定
Task<int> CloseWarningNotifyTaskAsync(Expression<Func<WarningNotifyTaskEntity, bool>> expression);
// 关闭预警通知任务

View File

@ -86,4 +86,9 @@ public class ReturnWarningDetailsIndex : IdBaseIndex
return TextJsonHelper.EqJsonStringField(extra, Extra, compareFields);
}
public bool MatchTrackTime(DateTime trackTime, float trackTimeZone)
{
return TrackTime == trackTime && Math.Abs(TrackTimeZone - trackTimeZone) < 0.1f;
}
}

View File

@ -22,15 +22,25 @@ public class TrackPushContentConfigVO
/// </summary>
public string ServiceProviderCode { get; set; } = null!;
/// <summary>
/// 推送顺序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 轨迹内容id
/// </summary>
public int TrackContentId { get; set; }
/// <summary>
/// 轨迹code
/// </summary>
public string TrackCode { get; set; } = null!;
/// <summary>
/// 推送顺序
/// 可交换顺序的轨迹内容id
/// </summary>
public int Sort { get; set; }
public int? SwapTrackContentId { get; set; }
/// <summary>
/// 可交换顺序的轨迹code

View File

@ -17,7 +17,6 @@ public class GetReturnWarningDetailsVO
public HashSet<int> Status { get; set; } = DefaultFollowStatus;
public Dictionary<int, HashSet<int>>? OrderIdTrackContentIdsDict { get; set; }
public Dictionary<int, HashSet<string>>? OrderIdTrackEsIdsDict { get; set; }
public HashSet<(int SubSystemId, int CustomId, int TrackContentId)>? PushConfigLinks { get; set; }
public bool HasDetailsIds => DetailsIds?.Count > 0;

View File

@ -137,9 +137,11 @@ public class TrackPushConfigRepository : BasicRepository<TrackPushConfigEntity>,
IsAllPush = a.IsAllPush,
ServiceProviderCode = a.ServiceProviderCode,
OrderType = b.OrderNoType,
TrackCode = d.Code,
SwapTrackCode = e.Code,
Sort = b.Sort,
TrackContentId = d.Id,
TrackCode = d.Code,
SwapTrackContentId = e.Id,
SwapTrackCode = e.Code,
TrackContentCodeValue = b.TrackContentCodeValue,
TrackContentValue = b.TrackContentValue,
TrackEnContentValue = b.TrackEnContentValue,

View File

@ -75,4 +75,20 @@ public class TrackStatusRepository : BasicRepository<TrackStatusEntity>, ITrackS
return pagedList;
}
public async Task<Dictionary<int, string>> GetTrackStatusIdNameDictAsync(HashSet<int> trackStatusIds)
{
if (trackStatusIds.Count == 0) return new Dictionary<int, string>(0);
var result = await Context.Queryable<TrackStatusEntity>()
.Where(x => trackStatusIds.Contains(x.Id))
.Select(x => new
{
x.Id,
x.Status
})
.ToListAsync();
return result.ToDictionary(x => x.Id, x => x.Status);
}
}

View File

@ -5,7 +5,7 @@ using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
namespace SJZY.Track.Repository.Repositories;
public sealed class WarningTaskRepository : BasicRepository<WarningNotifyTaskEntity>, IWarningTaskRepository
public sealed class WarningTaskRepository : BasicRepository<WarningNotifyTaskEntity>, IWarningTaskRepository, ITransientDependency
{
#region 预警通知任务