diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackByEsIdInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackByEsIdInput.cs new file mode 100644 index 00000000..681b3b75 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackByEsIdInput.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class BatchDeleteTrackByEsIdInput +{ + + /// + /// 轨迹内容es id,必填 + /// + [MaxLength(500)] + public List TrackContentEsIds { get; set; } = new(); +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs index 9d3a0a49..e1559126 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs @@ -14,6 +14,11 @@ public class TrackChangeEto /// public int SubSystemId { get; set; } + /// + /// 单号 + /// + public string OrderNo { get; set; } + /// /// 客户id /// diff --git a/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs index f395e972..7fba7153 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs @@ -7,6 +7,11 @@ public class TrackDeleteEvent /// public int SubSystemId { get; set; } + /// + /// es中的id + /// + public string[] EsIds { get; set; } + /// /// 订单ids /// diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs index 127305ac..92ca0dee 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs @@ -1,9 +1,14 @@ +using System.Text; +using BSI.Stack.Rabbit; using DotNetCore.CAP; using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; @@ -13,17 +18,26 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe { private readonly ICapPublisher _capPublisher; private readonly IOrderRepository _orderRepository; + private readonly ITrackStatusRepository _trackStatusRepository; + private readonly ITrackContentRepository _trackContentRepository; private readonly IProvideQueries _provideQueries; private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly RabbitClientBus _rabbitClientBus; public TrackDeleteEventHandler(IProvideQueries provideQueries, IOrderRepository orderRepository, ICapPublisher capPublisher, - ITrackDetailsEsRepository trackDetailsEsRepository) + ITrackDetailsEsRepository trackDetailsEsRepository, + RabbitClientBus rabbitClientBus, + ITrackStatusRepository trackStatusRepository, + ITrackContentRepository trackContentRepository) { _provideQueries = provideQueries; _orderRepository = orderRepository; _capPublisher = capPublisher; _trackDetailsEsRepository = trackDetailsEsRepository; + _rabbitClientBus = rabbitClientBus; + _trackStatusRepository = trackStatusRepository; + _trackContentRepository = trackContentRepository; } [CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)] @@ -31,7 +45,10 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe { if (!CanDelete(@event)) return; - await DeleteTrackAsync(@event); + var trackList = await DeleteTrackAsync(@event); + + //发布事件 + await PublicTrackTopicAsync(@event, trackList); // 根据订单关联关系异步向下刷(异步) await DownByOrderLink(@event); @@ -84,12 +101,8 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe private bool CanDelete(TrackDeleteEvent @event) { - // 系统创建的轨迹不允许删除 - if (@event.Visited.IsNullOrEmpty() && @event.OperationMan == GlobalConst.SystemUser) - { - LogHelper.Warn($"系统创建的轨迹不允许被删除:{@event}", true); - return false; - } + if (@event.OrderIds == null) + return true; // 订单循环关联检测 var dup = @event.Visited.Intersect(@event.OrderIds).ToArray(); @@ -102,14 +115,79 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe return true; } - private async Task DeleteTrackAsync(TrackDeleteEvent @event) + private async Task PublicTrackTopicAsync(TrackDeleteEvent eto, List trackList) { - // 删除轨迹(删的是同子系统下的单,所以code是统一的) - var tracks = await _trackDetailsEsRepository.GetLatestListAsync(@event.OrderIds, @event.TrackCodes); + if (trackList == null) + return; - var orderIds = await _trackDetailsEsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes); + var statusList = await _trackStatusRepository.GetListAsync(m => m.SubSystemId == eto.SubSystemId); + if (statusList == null) + return; + + var contentList = await _trackContentRepository.GetTrackContentBySyetemIdAsync(eto.SubSystemId); + if (contentList == null) + return; + + foreach (var dataItem in trackList.GroupBy(m => new + { + m.TrackCode, + m.OrderNo + })) + { + var item = dataItem.First(); + var status = statusList.FirstOrDefault(m => m.Code == item.TrackStatusCode); + if (status == null || !status.IsToMq) + continue; + + var content = contentList.FirstOrDefault(m => m.TrackContentCode == item.TrackCode); + + var data = new TrackChangeEto() + { + OrderIdentifiers = dataItem.Select(m => new OrderIdentifier + { + OrderId = m.OrderId, + OrderNo = m.OrderNo, + OrderType = m.OrderType + }).ToArray(), + TrackStatusCode = item.TrackStatusCode, + TrackCode = item.TrackCode, + OperationMan = eto.OperationMan, + SubSystemId = eto.SubSystemId, + Option = 2 + }; + + _rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{content.SubSystemCode}", Encoding.UTF8.GetBytes(data.ToJson())); + } + } + + private async Task> DeleteTrackAsync(TrackDeleteEvent @event) + { + List orderIds; + List tracks; + if (@event.EsIds != null && @event.EsIds.Any()) //根据明确的esid进行删除 + { + tracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds); + orderIds = tracks.Select(m => m.OrderId).Distinct().ToList(); + + // 外部api获取的轨迹不允许删除 + if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) + return tracks; + + // 删除轨迹 + foreach (var item in tracks) + { + await _trackDetailsEsRepository.DeleteTrackByIdAsync(item.Id, item.IndexName); + } + } + else //原有逻辑,根据轨迹code和订单进行删除 + { + // 删除轨迹(删的是同子系统下的单,所以code是统一的) + tracks = await _trackDetailsEsRepository.GetLatestListAsync(@event.OrderIds, @event.TrackCodes); + + orderIds = await _trackDetailsEsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes); + if (orderIds.Count == 0) return tracks; + } - if (orderIds.Count == 0) return; var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => new OrderEntity @@ -121,8 +199,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe LatestTrackTime = x.LatestTrackTime, LatestTrackTimeZone = x.LatestTrackTimeZone, }); - - if (orders.Count == 0) return; + if (orders.Count == 0) return tracks; foreach (var order in orders) { @@ -157,5 +234,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe x.LatestTrackTime, x.LatestTrackTimeZone }); + + return tracks; } } diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs index 07859810..ce0c265e 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs @@ -43,6 +43,8 @@ public partial class OrderService : ApplicationService, IOrderService throw new BusinessException(message: "【目的地时区】和【预计到达时间】必须同时输入"); } + var currentUser = CurrentUserRequest.CurrentUser; + // 校验订单是否已存在,存在则更新 var order = await _orderRepository.GetFirstAsync(x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo); @@ -55,8 +57,10 @@ public partial class OrderService : ApplicationService, IOrderService { OrderId = order.Id, OrderNo = input.OrderNo, - OptionType = OptionType.修改.ToString(), + OptionType = OrderOperationType.修改订单.ToString(), Content = input.ToJson(), + CreateUserId = currentUser.UserId, + CreateUserString = currentUser.Name, }; _ = _orderOperationRecordEsRepository.AddAsync(index); @@ -71,18 +75,20 @@ public partial class OrderService : ApplicationService, IOrderService order.SubSystemId = input.SubSystemId; order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos); - order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos); + order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos); var orderId = await _orderRepository.CreateOrderAsync(order); // 写入操作日志 + var indexForAdd = new OrderOperationRecordIndex { OrderId = orderId, OrderNo = input.OrderNo, - OptionType = OptionType.新增.ToString(), + OptionType = OrderOperationType.创建订单.ToString(), Content = input.ToJson(), - CreateUserId = CurrentUserRequest.CurrentUser.UserId, + CreateUserId = currentUser.UserId, + CreateUserString = currentUser.Name, CreateTime = DateTime.Now }; _ = _orderOperationRecordEsRepository.AddAsync(indexForAdd); @@ -156,7 +162,8 @@ public partial class OrderService : ApplicationService, IOrderService return status; }).ToList(); } - private List BuiltOrderPlatformNumbers(List? pullConfigInfos) + + private List BuiltOrderPlatformNumbers(List? pullConfigInfos) { if (pullConfigInfos == null) return new List(); @@ -165,9 +172,9 @@ public partial class OrderService : ApplicationService, IOrderService var status = new OrderPlatformNumberEntity { //三方单号 - OrderNumber = x.OrderNo, - //三方平台名称,目前认为是服务商code - Platform = x.ServiceCode, + OrderNumber = x.OrderNo, + //三方平台名称,目前认为是服务商code + Platform = x.ServiceCode, }; return status; diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index 37a6e394..a1d373f0 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -175,6 +175,42 @@ public partial class TrackService : ApplicationService, ITrackService return new UnifyResultDto(true, true); } + /// + /// 根据esid删除轨迹内容 + /// + /// + /// + [HttpPost("Track/BatchDeleteByEsId")] + public async Task BatchDeleteTrackByEsIdAsync(BatchDeleteTrackByEsIdInput input) + { + var tracks = await _trackDetailsEsRepository.GetDataByIds(input.TrackContentEsIds.ToArray()); + if (tracks == null || tracks.Count == 0) + return new UnifyResultDto(false, "未找到指定id下的轨迹内容"); + + if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) + return new UnifyResultDto(false, "存在来源于外部服务商的轨迹,不允许删除"); + + if (tracks.GroupBy(m => m.SubSystemId).Count() > 1) + return new UnifyResultDto(false, "暂不支持跨子系统批量删除"); + + // 获取用户name + var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) + { + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); + } + + // 删除轨迹 + var @event = new TrackDeleteEvent + { + EsIds = input.TrackContentEsIds.ToArray(), + SubSystemId = tracks.First().SubSystemId, + OperationMan = userInfo.Data.UserName, + }; + await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + + return new UnifyResultDto(true); + } /// /// 批量删除轨迹 @@ -217,7 +253,7 @@ public partial class TrackService : ApplicationService, ITrackService OrderIds = orderIds.ToArray(), TrackCodes = input.TrackCodes, SubSystemId = input.SubSystemId, - OperationMan = userInfo.Data.UserName + OperationMan = userInfo.Data.UserName, }; await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs index cedba47d..df044ff6 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs @@ -40,8 +40,22 @@ public class OrderOperationRecordIndex : IdBaseIndex /// public int CreateUserId { get; set; } + /// + /// 创建人姓名 + /// + public string CreateUserString { get; set; } + /// /// 创建时间 /// public DateTime CreateTime { get; set; } } + +public enum OrderOperationType +{ + 创建订单 = 1, + 修改订单 = 2, + 创建轨迹 = 3, + 修改轨迹 = 4, + 删除轨迹 = 5 +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs index b321e87b..fe3a81d7 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs @@ -28,4 +28,5 @@ public interface ITrackContentRepository : IBasicRepository Task GetTemplateIsExist(int trackContentId); Task GetByCodeAsync(int systemId, string code); Task> GetListBySystemIdAsync(int systemId); + Task> GetTrackContentBySyetemIdAsync(int subSystemId); } diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs index f68269ff..a8da5185 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs @@ -28,4 +28,5 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService> DeleteTrackAsync(int[] orderIds, List trackCodes); Task DeleteTrackByIdAsync(string id, string indexName); + Task> GetDataByIds(string[] ids); } diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs index f084b0a8..8b7cdf3f 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs @@ -56,4 +56,9 @@ public class TrackContentVO /// 是否广播 /// public bool IsToMq { get; set; } + + /// + /// 轨迹内容code + /// + public string TrackContentCode { get; set; } } diff --git a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs index 6ce6a15c..d619613b 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs @@ -248,4 +248,27 @@ public class TrackContentRepository : BasicRepository, ITrac }) .ToListAsync(); } + + public Task> GetTrackContentBySyetemIdAsync(int subSystemId) + { + return Context.Queryable() + .LeftJoin((x, y) => x.TrackStatusId == y.Id) + .LeftJoin((x, y, z) => x.SubSystemId == z.Id) + .Where(x => x.SubSystemId == subSystemId) + .Select((x, y, z) => new TrackContentVO + { + SubSystemCode = z.Key, + TrackStatusId = x.TrackStatusId, + TrackStatus = y.Status, + TrackStatusCode = y.Code, + TrackContent = x.Content, + TrackContentCode = x.Code, + TrackEnContent = x.EnContent, + IsCompleted = y.IsCompleted, + IsRepeatable = x.IsRepeatable, + IsAllowManuallyUpdate = x.IsAllowManuallyUpdate, + IsAllowManuallyCreate = x.IsAllowManuallyCreate, + IsToMq = y.IsToMq, + }).ToListAsync(); + } } diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs index 014c0c45..beb8dc0a 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs @@ -408,6 +408,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract x.OrderId).ToList(); } + public async Task DeleteTrackByIdAsync(string id, string indexName) { var r = await Context.DeleteAsync(id, u => u @@ -419,4 +420,15 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetDataByIds(string[] ids) + { + var res = await Context.SearchAsync(m => m + .Index(GlobalConst.TrackDetailsIndex) + .Query( + q => q.Ids(i => i.Values(ids)) + )); + + return res.ToIdList(); + } }