Merge branch 'S03-轨迹中台优化项' into dev

This commit is contained in:
李鹏军 2024-04-12 21:35:34 +08:00
commit 594a76b5df
51 changed files with 1106 additions and 619 deletions

View File

@ -5,17 +5,18 @@ public class GetTrackOutput
/// <summary> /// <summary>
/// 订单号 /// 订单号
/// </summary> /// </summary>
public string OrderNo { get; set; } public string OrderNo { get; set; } = null!;
public List<TrackDetail> TrackDetails { get; set; } public List<TrackDetail> TrackDetails { get; set; } = new();
} }
public class TrackDetail public class TrackDetail
{ {
public string Code { get; set; } public string Code { get; set; } = null!;
public string Status { get; set; } public string Status { get; set; } = null!;
public string Content { get; set; } public string? Content { get; set; }
public string Location { get; set; } public string? OriginContent { get; set; }
public string Location { get; set; } = null!;
public DateTime Time { get; set; } public DateTime Time { get; set; }
public float TimeZone { get; set; } public float TimeZone { get; set; }
} }

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SJZY.Track.Application.Contract.Dtos.ProvideServices
{
/// <summary>
/// 查询轨迹推送映射关系入参
/// </summary>
public class QueryTrackPullMappingsInput
{
/// <summary>
/// 子系统id
/// </summary>
public int SubsystemsId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomerId { get; set; }
}
/// <summary>
/// 查询轨迹推送映射关系返参项
/// </summary>
public class QueryTrackPullMappingsInfo
{
/// <summary>
/// 轨迹代码
/// </summary>
public string? Code { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 服务商轨迹代码
/// </summary>
public string? ServiceCode { get; set; }
/// <summary>
/// 服务商轨迹状态
/// </summary>
public string? Status { get; set; }
/// <summary>
/// 服务商轨迹内容
/// </summary>
public string? Content { get; set; }
/// <summary>
/// 服务商轨迹内容英文
/// </summary>
public string? ContentEn { get; set; }
}
}

View File

@ -88,7 +88,7 @@
/// <summary> /// <summary>
/// 轨迹标记id /// 轨迹标记id
/// </summary> /// </summary>
public int TrackFlagId { get; set; } public int? TrackFlagId { get; set; }
/// <summary> /// <summary>
/// 轨迹标记 /// 轨迹标记

View File

@ -0,0 +1,75 @@
namespace SJZY.Track.Application.Contract.Dtos.TrackOrder;
public class TrackPushRecordOutput
{
/// <summary>
/// 订单Id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 接口通请求Id
/// </summary>
public Guid RequestId { get; set; }
/// <summary>
/// 信息
/// </summary>
public string Message { get; set; } = null!;
/// <summary>
/// 操作类型
/// </summary>
public string OptionType { get; set; } = null!;
/// <summary>
/// 轨迹状态
/// </summary>
public string TrackStatus { get; set; } = null!;
/// <summary>
/// 轨迹内容代码
/// </summary>
public string TrackCode { get; set; } = null!;
/// <summary>
/// 轨迹内容
/// </summary>
public string TrackContent { get; set; } = null!;
/// <summary>
/// 轨迹发生地
/// </summary>
public string TrackPlace { get; set; } = null!;
/// <summary>
/// 轨迹发生时间
/// </summary>
public DateTime TrackTime { get; set; }
/// <summary>
/// 轨迹发生时区
/// </summary>
public float TrackTimeZone { get; set; }
/// <summary>
/// 轨迹发生时区
/// </summary>
public string TrackGTMTimeZone { get; set; } = null!;
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 推送内容(json)
/// </summary>
public string PushContent { get; set; } = null!;
/// <summary>创建人</summary>
public string? CreateUser { get; set; }
/// <summary>创建时间</summary>
public DateTime CreateTime { get; set; }
}

View File

@ -0,0 +1,20 @@
namespace SJZY.Track.Application.Contract.Dtos.TrackPush;
public class TrackPushInput
{
public string OrderNo { get; set; } = null!;
public List<TrackItem> Data { get; set; } = new();
}
public class TrackItem
{
public string Location { get; set; } = null!;
public DateTime Date { get; set; }
public double TimeZone { get; set; }
public string? Description { get; set; }
public string? DescriptionCn { get; set; }
public string? Code { get; set; }
public string? Status { get; set; }
public string? Extra { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace SJZY.Track.Application.Contract.Events;
public struct OrderIdentifier
{
public int OrderId { get; set; }
public string OrderNo { get; set; }
public int OrderType { get; set; }
}

View File

@ -1,28 +0,0 @@
namespace SJZY.Track.Application.Contract.Events;
public class OrderLinkAfterFillTrackEvent
{
/// <summary>
/// 关联订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 关联订单
/// </summary>
public List<LinkedOrder> LinkedOrders { get; set; } = null!;
}
public struct LinkedOrder
{
public int SubSystemId { get; set; }
public int OrderId { get; set; }
public string OrderNo { get; set; }
public int OrderType { get; set; }
}

View File

@ -5,7 +5,7 @@ public class TrackChangeAfterUpdateOrderEvent
/// <summary> /// <summary>
/// 订单Id /// 订单Id
/// </summary> /// </summary>
public int OrderId { get; set; } public int[] OrderIds { get; set; }
/// <summary> /// <summary>
/// 是否删除引起的更新 /// 是否删除引起的更新

View File

@ -2,25 +2,20 @@
public class TrackDeleteEvent public class TrackDeleteEvent
{ {
/// <summary>
/// 订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 轨迹代码
/// </summary>
public List<string> TrackCodes { get; set; } = null!;
/// <summary> /// <summary>
/// 子系统id /// 子系统id
/// </summary> /// </summary>
public int SubSystemId { get; set; } public int SubSystemId { get; set; }
/// <summary> /// <summary>
/// 上游子系统id /// 订单ids
/// </summary> /// </summary>
public int UpSubSystemId { get; set; } public int[] OrderIds { get; set; } = null!;
/// <summary>
/// 轨迹代码
/// </summary>
public List<string> TrackCodes { get; set; } = null!;
/// <summary> /// <summary>
/// 操作人 /// 操作人

View File

@ -0,0 +1,25 @@
namespace SJZY.Track.Application.Contract.Events;
public struct TrackRefreshStruct
{
/// <summary>
/// 服务商
/// </summary>
public string? ServiceProviderName { get; set; }
/// <summary>
/// 原轨迹内容
/// </summary>
public string? OriginTrackContent { get; set; }
/// <summary>
/// 原轨迹报文
/// </summary>
public string? OriginTrackData { get; set; }
/// <summary>
/// 表示订单是否完成(只由轨迹刷新配置决定)
/// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新
/// </summary>
public bool IsCompleted { get; set; }
}

View File

@ -3,40 +3,14 @@
public class TrackUpsertEvent public class TrackUpsertEvent
{ {
/// <summary> /// <summary>
/// 订单id /// 子系统id(操作的订单都是相同子系统下的)
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; } = null!;
/// <summary>
/// 服务商
/// </summary>
public string? ServiceProviderName { get; set; }
/// <summary>
/// 表示订单是否完成(只由轨迹刷新配置决定)
/// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新
/// </summary>
public bool IsCompleted { get; set; }
/// <summary>
/// 子系统id
/// </summary> /// </summary>
public int SubSystemId { get; set; } public int SubSystemId { get; set; }
/// <summary> /// <summary>
/// 上游子系统id(0表示事件起点) /// 订单id
/// </summary> /// </summary>
public int UpSubSystemId { get; set; } public OrderIdentifier[] OrderIdentifiers { get; set; } = null!;
/// <summary> /// <summary>
/// 操作人(null则默认系统) /// 操作人(null则默认系统)
@ -44,7 +18,7 @@ public class TrackUpsertEvent
public string? OperationMan { get; set; } public string? OperationMan { get; set; }
/// <summary> /// <summary>
/// true新增,false更新,null表示新增/更新 /// true新增,false更新,null表示刷新
/// </summary> /// </summary>
public bool? IsAdd { get; set; } public bool? IsAdd { get; set; }
@ -72,4 +46,6 @@ public class TrackUpsertEvent
/// 已经处理过的订单 /// 已经处理过的订单
/// </summary> /// </summary>
public List<int> Visited { get; set; } = new(); public List<int> Visited { get; set; } = new();
public TrackRefreshStruct TrackRefreshData { get; set; }
} }

View File

@ -0,0 +1,94 @@
namespace SJZY.Track.Application.Contract.Events;
public class TrackUpsertForRefreshEvent
{
/// <summary>
/// 子系统id(操作的订单都是相同子系统下的)
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 订单
/// </summary>
public OrderIdentifier OrderIdentifiers { get; set; }
/// <summary>
/// 服务商
/// </summary>
public string? ServiceProviderName { get; set; }
/// <summary>
/// 原轨迹内容
/// </summary>
public string? OriginTrackContent { get; set; }
/// <summary>
/// 原轨迹报文
/// </summary>
public string? OriginTrackData { get; set; }
/// <summary>
/// 表示订单是否完成(只由轨迹刷新配置决定)
/// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新
/// </summary>
public bool IsCompleted { get; set; }
/// <summary>
/// 轨迹内容代码
/// </summary>
public string TrackCode { get; set; } = null!;
/// <summary>
/// 轨迹发生地
/// </summary>
public string TrackPlace { get; set; } = null!;
/// <summary>
/// 轨迹发生时间
/// </summary>
public DateTime TrackTime { get; set; }
/// <summary>
/// 轨迹发生时区
/// </summary>
public float TrackTimeZone { get; set; }
}
public class TrackHandledDto
{
/// <summary>
/// 原轨迹内容
/// </summary>
public string? OriginTrackContent { get; set; }
/// <summary>
/// 原轨迹报文
/// </summary>
public string? OriginTrackData { get; set; }
/// <summary>
/// 表示订单是否完成(只由轨迹刷新配置决定)
/// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新
/// </summary>
public bool? IsCompleted { get; set; }
/// <summary>
/// 轨迹内容代码
/// </summary>
public string? TrackCode { get; set; }
/// <summary>
/// 轨迹发生地
/// </summary>
public string? TrackPlace { get; set; }
/// <summary>
/// 轨迹发生时间
/// </summary>
public DateTime? TrackTime { get; set; }
/// <summary>
/// 轨迹发生时区
/// </summary>
public float? TrackTimeZone { get; set; }
}

View File

@ -5,7 +5,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<GenerateDocumentationFile>True</GenerateDocumentationFile> <GenerateDocumentationFile>True</GenerateDocumentationFile>
<Version>7.0.0</Version> <Version>7.0.2</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile> <GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -12,6 +12,14 @@ public interface ITrackPushCacheService
/// <returns></returns> /// <returns></returns>
Task<List<TrackPushContentConfigDto>?> GetPushContentConfigsAsync(int subSystemId, int customId); Task<List<TrackPushContentConfigDto>?> GetPushContentConfigsAsync(int subSystemId, int customId);
/// <summary>
/// 设置服务商拉取配置缓存
/// </summary>
/// <param name="subSystemId"></param>
/// <param name="customId"></param>
/// <returns></returns>
Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int subSystemId, int customId);
/// <summary> /// <summary>
/// 获取服务商拉取配置 /// 获取服务商拉取配置
/// </summary> /// </summary>
@ -33,14 +41,4 @@ public interface ITrackPushCacheService
Task<TrackPushContentConfigDto?> IsValidPushAsync(int subSystemId, int customId, Task<TrackPushContentConfigDto?> IsValidPushAsync(int subSystemId, int customId,
string? latestPushTrackCode, string? latestPushTrackCode,
string? trackCode); string? trackCode);
/// <summary>
/// 设置推送配置缓存
/// </summary>
/// <param name="id"></param>
/// <param name="subSystemId">子系统id</param>
/// <param name="customId">客户id</param>
/// <returns></returns>
Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int? id = null, int? subSystemId = null,
int? customId = null);
} }

View File

@ -0,0 +1,20 @@
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
namespace SJZY.Track.Application.Contract.Services
{
public interface ITrackPushConfigService : IRemoteService
{
/// <summary>
/// 查询轨迹推送配置关系
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<UnifyResultDto> QueryTrackPullMappingsAsync(QueryTrackPullMappingsInput input);
}
}

View File

@ -31,5 +31,5 @@ public interface ITrackService : IRemoteService
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
Task<List<GetTrackOutput>> QueryAsync(GetTrackInput input); Task<UnifyResultDto> QueryAsync(GetTrackInput input);
} }

View File

@ -1,8 +1,10 @@
using AutoMapper; using AutoMapper;
using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Dtos.TrackOrder;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Dtos.Order;
using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Enums;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
@ -34,6 +36,8 @@ public class OrderAutoMapperProfile : Profile
.ForMember(dest => dest.Content, opt => opt.MapFrom(m => m.TrackContent)) .ForMember(dest => dest.Content, opt => opt.MapFrom(m => m.TrackContent))
.ForMember(dest => dest.EnContent, opt => opt.MapFrom(m => m.TrackEnContent)) .ForMember(dest => dest.EnContent, opt => opt.MapFrom(m => m.TrackEnContent))
.ForMember(dest => dest.TrackTimeZoneValue, opt => opt.MapFrom(m => m.TrackTimeZone)); .ForMember(dest => dest.TrackTimeZoneValue, opt => opt.MapFrom(m => m.TrackTimeZone));
CreateMap<TrackPushRecordIndex, TrackPushRecordOutput>(MemberList.None);
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,22 @@
using AutoMapper;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Dtos.TrackPush;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Dtos.TrackPush;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SJZY.Track.Application.AutoMapper
{
public class TrackPushConfigAutoMapperProfile : Profile
{
public TrackPushConfigAutoMapperProfile()
{
CreateMap<QueryTrackPullMappingsInput, QueryTrackPullMappingsInputVO>(MemberList.None);
CreateMap<QueryTrackPullMappingsInfoVO, QueryTrackPullMappingsInfo>(MemberList.None);
}
}
}

View File

@ -20,8 +20,9 @@ public class CapFilter : SubscribeFilter
{ {
context.DeliverMessage.Headers["sjzy-receive-time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"); context.DeliverMessage.Headers["sjzy-receive-time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff");
// 轨迹刷新不做幂等 // 轨迹增删改要做幂等
if (context.DeliverMessage.Headers["cap-msg-name"]!.EndsWith(GlobalConst.TrackRefreshSubscribe)) if (!context.DeliverMessage.Headers["cap-msg-name"]
.IsIn(GlobalConst.TrackUpsertSubscribe, GlobalConst.TrackDeleteSubscribe))
return Task.CompletedTask; return Task.CompletedTask;
// 本地调试不做幂等 // 本地调试不做幂等

View File

@ -1,52 +0,0 @@
using DotNetCore.CAP;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Consts;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.EventHandlers;
public class OrderLinkAfterFillTrackHandler : ITransientDependency, ICapSubscribe
{
private readonly ITrackDetailsRepository _trackDetailsRepository;
private readonly ICapPublisher _capPublisher;
private readonly IOrderRepository _orderRepository;
public OrderLinkAfterFillTrackHandler(ITrackDetailsRepository trackDetailsRepository, ICapPublisher capPublisher,
IOrderRepository orderRepository)
{
_trackDetailsRepository = trackDetailsRepository;
_capPublisher = capPublisher;
_orderRepository = orderRepository;
}
[CapSubscribe(GlobalConst.OrderLinkAfterFillTrack)]
public async Task ConsumerAsync(OrderLinkAfterFillTrackEvent @event)
{
var tracks = await _trackDetailsRepository.GetListAsync(@event.OrderId);
foreach (var order in @event.LinkedOrders)
{
// 补轨迹
foreach (var track in tracks)
{
var fillTrackEvent = new TrackUpsertEvent
{
OrderId = order.OrderId,
OrderType = order.OrderType,
OrderNo = order.OrderNo,
TrackCode = track.TrackCode,
TrackPlace = track.TrackPlace,
TrackTime = track.TrackTime,
TrackTimeZone = track.TrackTimeZone,
SubSystemId = order.SubSystemId,
UpSubSystemId = @event.SubSystemId,
};
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, fillTrackEvent);
}
}
}
}

View File

@ -22,13 +22,28 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
[CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)]
public async Task ConsumerAsync(TrackChangeAfterUpdateOrderEvent @event) public async Task ConsumerAsync(TrackChangeAfterUpdateOrderEvent @event)
{ {
var order = await _orderRepository.GetFirstAsync(x => x.Id == @event.OrderId); var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id),
if (order == default) return; x => new OrderEntity
{
Id = x.Id,
IsCompleted = x.IsCompleted,
LatestTrackContent = x.LatestTrackContent,
LatestTrackEnContent = x.LatestTrackEnContent,
LatestTrackPlace = x.LatestTrackPlace,
LatestTrackTime = x.LatestTrackTime,
LatestTrackTimeZone = x.LatestTrackTimeZone,
});
if (orders.Count == 0) return;
// todo:delete可能发生回退,直接去es查最新轨迹,但是可能es还没有刷盘,导致回退失效,可以考虑加个定时任务弥补
if (@event.IsDelete) if (@event.IsDelete)
{ {
var track = await _trackDetailsRepository.GetLatestAsync(@event.OrderId); foreach (var order in orders)
{
var tracks = await _trackDetailsRepository.GetListAsync(@event.OrderIds);
var track = tracks.Where(x => x.OrderId == order.Id).MaxBy(x => x.TrackTime);
// 删除全部轨迹导致的重置行为 // 删除全部轨迹导致的重置行为
if (track == default) if (track == default)
{ {
@ -36,12 +51,9 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
// tips:订单是支持从已完成态到未完成态的 // tips:订单是支持从已完成态到未完成态的
order.ResetTrackInfo(); order.ResetTrackInfo();
await _orderRepository.UpdateAsync(order);
return;
} }
else
{
// 删除引发的回退更新 // 删除引发的回退更新
order.IsCompleted = @event.IsCompleted; order.IsCompleted = @event.IsCompleted;
order.LatestTrackContent = track.TrackContent; order.LatestTrackContent = track.TrackContent;
@ -50,13 +62,17 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
order.LatestTrackTime = track.TrackTime; order.LatestTrackTime = track.TrackTime;
order.LatestTrackTimeZone = track.TrackTimeZone; order.LatestTrackTimeZone = track.TrackTimeZone;
} }
else }
}
else // upsert可以直接计算
{
foreach (var order in orders)
{ {
if (order.LatestTrackTime != null && if (order.LatestTrackTime != null &&
@event.TrackTime.Subtract(TimeSpan.FromHours(@event.TrackTimeZone)) < @event.TrackTime.Subtract(TimeSpan.FromHours(@event.TrackTimeZone)) <
order.LatestTrackTime.Value.Subtract(TimeSpan.FromHours(order.LatestTrackTimeZone ?? 0))) order.LatestTrackTime.Value.Subtract(TimeSpan.FromHours(order.LatestTrackTimeZone ?? 0)))
{ {
return; continue;
} }
// upsert引发的更新 // upsert引发的更新
@ -67,8 +83,9 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
order.LatestTrackTime = @event.TrackTime; order.LatestTrackTime = @event.TrackTime;
order.LatestTrackTimeZone = @event.TrackTimeZone; order.LatestTrackTimeZone = @event.TrackTimeZone;
} }
}
await _orderRepository.UpdateColumnAsync(order, x => new await _orderRepository.UpdateRangeAsync(orders, x => new
{ {
x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime,
x.LatestTrackTimeZone x.LatestTrackTimeZone

View File

@ -29,17 +29,33 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
[CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)] [CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)]
public async Task ConsumerAsync(TrackDeleteEvent @event) public async Task ConsumerAsync(TrackDeleteEvent @event)
{ {
if (@event.Visited.Contains(@event.OrderId)) var dup = @event.Visited.Intersect(@event.OrderIds).ToArray();
if (dup.Any())
{ {
LogHelper.Error($"删除轨迹订单时,发现循环依赖:{@event.Visited.JoinAsString(",")}"); LogHelper.Error($"删除轨迹订单时,发现循环依赖:{dup.JoinAsString(",")}");
return; return;
} }
await DeleteTrackAsync(@event);
// 根据订单关联关系异步向下刷(异步)
var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderIds);
foreach (var orderId in @event.OrderIds)
{
foreach (var group in linkedOrders.Where(x => x.OrderId == orderId)
.GroupBy(x => x.SubSystemId))
{
var nextEvent = @event.DeepCopy();
nextEvent.Visited.AddRange(@event.OrderIds);
nextEvent.TrackCodes = @event.TrackCodes;
nextEvent.SubSystemId = group.Key;
// 不同子系统需要做内容映射 // 不同子系统需要做内容映射
if (@event.UpSubSystemId != 0 && @event.UpSubSystemId != @event.SubSystemId) if (@event.SubSystemId != nextEvent.SubSystemId)
{ {
var mapCodes = await _provideQueries var mapCodes = await _provideQueries
.MapTrackCodesAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCodes.ToArray()); .MapTrackCodesAsync(@event.SubSystemId, nextEvent.SubSystemId, @event.TrackCodes.ToArray());
if (mapCodes.Count == 0) if (mapCodes.Count == 0)
{ {
@ -47,16 +63,18 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
return; return;
} }
@event.TrackCodes = mapCodes; nextEvent.TrackCodes = mapCodes;
} }
await DeleteTrackAsync(@event); await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, nextEvent);
}
}
} }
private async Task DeleteTrackAsync(TrackDeleteEvent @event) private async Task DeleteTrackAsync(TrackDeleteEvent @event)
{ {
// 删除轨迹 // 删除轨迹(删的是同子系统下的单,所以code是统一的)
var isOk = await _trackDetailsRepository.DeleteTrackAsync(@event.OrderId, @event.TrackCodes); var isOk = await _trackDetailsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes);
if (isOk) if (isOk)
{ {
@ -65,22 +83,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
GlobalConst.TrackChangeAfterUpdateOrderSubscribe, GlobalConst.TrackChangeAfterUpdateOrderSubscribe,
new TrackChangeAfterUpdateOrderEvent new TrackChangeAfterUpdateOrderEvent
{ {
OrderId = @event.OrderId, OrderIds = @event.OrderIds,
IsDelete = true IsDelete = true
}); });
} }
// 根据订单关联关系异步向下刷
var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderId);
foreach (var linkedOrder in linkedOrders)
{
var nextEvent = @event.DeepCopy();
nextEvent.Visited.Add(@event.OrderId);
nextEvent.TrackCodes = @event.TrackCodes;
nextEvent.SubSystemId = linkedOrder.SubSystemId;
nextEvent.UpSubSystemId = @event.SubSystemId;
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, nextEvent);
}
} }
} }

View File

@ -45,6 +45,6 @@ public class TrackInsertForNotMappedEventHandler : ITransientDependency, ICapSub
track.TrackEnContent = GlobalConst.EmptyString; track.TrackEnContent = GlobalConst.EmptyString;
track.ZeroTrackTime = track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); track.ZeroTrackTime = track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
await _trackDetailsRepository.UpsertAsync(track); await _trackDetailsRepository.UpdateAsync(track);
} }
} }

View File

@ -1,50 +0,0 @@
using DotNetCore.CAP;
using SJZY.Track.Application.Contract.Dtos.TrackPush;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Consts;
using SJZY.Track.Domain.Enums;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.EventHandlers;
public class TrackPushAfterUpdateOrderEventHandler : ITransientDependency, ICapSubscribe
{
private readonly IOrderRepository _orderRepository;
public TrackPushAfterUpdateOrderEventHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
[CapSubscribe(GlobalConst.TrackPushAfterUpdateOrderSubscribe)]
public async Task ConsumerAsync(TrackPushAfterUpdateOrderDto dto)
{
var order = await _orderRepository.GetFirstAsync(x => x.Id == dto.OrderId);
if (order == default) return;
/*
* 异常:最近一条推送是失败
*/
if (!dto.IsSuccess)
{
order.QuestionType = (int)TrackProblemType.Error;
order.LatestPushError = dto.Message;
}
else
{
order.QuestionType = (int)TrackProblemType.None;
order.LatestPushError = null;
if (dto.OptionType == OptionType.新增)
{
// tips:只有新增会影响推送进度
order.LatestPushTrackCode = dto.TrackCode;
order.LatestPushTime = DateTime.Now;
}
}
await _orderRepository.UpdateColumnAsync(order, x => new
{
x.LatestPushTrackCode, x.QuestionType, x.LatestPushError, x.LatestPushTime
});
}
}

View File

@ -1,5 +1,5 @@
using DotNetCore.CAP; using DotNetCore.CAP;
using Newtonsoft.Json.Linq; using Newtonsoft.Json;
using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.InterfaceRelay.Application.Contracts; using SJZY.InterfaceRelay.Application.Contracts;
using SJZY.Track.Application.Contract.Dtos.TrackPush; using SJZY.Track.Application.Contract.Dtos.TrackPush;
@ -37,11 +37,9 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
var order = await _orderRepository.GetFirstAsync(x => var order = await _orderRepository.GetFirstAsync(x =>
x.Id == @event.OrderId, x => new x.Id == @event.OrderId, x => new
{ {
x.SubSystemId, x.LatestPushTrackCode, x.QuestionType, x.CustomId x.SubSystemId, x.LatestPushTrackCode, x.QuestionType, x.CustomId, x.OrderType
}); });
if (order == null || order.QuestionType == (int)TrackProblemType.Error) return; // 是否通知? if (order == null) return;
TrackPushContentConfigDto? config;
var log = new TrackPushRecordIndex var log = new TrackPushRecordIndex
{ {
@ -58,16 +56,24 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
CreateTime = DateTime.Now CreateTime = DateTime.Now
}; };
TrackPushContentConfigDto? config = null;
switch (@event.OptionType) switch (@event.OptionType)
{ {
case OptionType.无: case OptionType.无:
return; return;
case OptionType.新增: case OptionType.新增:
if (@event.OperationMan == null) if (@event.OperationMan == null)
{
if (order.QuestionType != (int)TrackProblemType.Error)
{ {
// 推送新增,需要根据上一次的推送 推断 本次推送 是否可行 // 推送新增,需要根据上一次的推送 推断 本次推送 是否可行
config = await _trackPushCacheService.IsValidPushAsync(order.SubSystemId, order.CustomId, config = await _trackPushCacheService.IsValidPushAsync(order.SubSystemId, order.CustomId,
order.LatestPushTrackCode, @event.TrackCode); order.LatestPushTrackCode, @event.TrackCode);
if (config == null) return;
if (!config.IsAutoPush) return;
if (config.OrderType != order.OrderType) return;
}
} }
else else
{ {
@ -132,45 +138,50 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
// tips:只有新增会影响推送进度? // tips:只有新增会影响推送进度?
order.LatestPushTrackCode = dto.TrackCode; order.LatestPushTrackCode = dto.TrackCode;
order.LatestPushTime = DateTime.Now; order.LatestPushTime = DateTime.Now;
await _orderRepository.UpdateColumnAsync(order, x => new
{
x.LatestPushTrackCode, x.LatestPushTime, x.QuestionType, x.LatestPushError
});
return;
} }
} }
await _orderRepository.UpdateColumnAsync(order, x => new await _orderRepository.UpdateColumnAsync(order, x => new
{ {
x.LatestPushTrackCode, x.QuestionType, x.LatestPushError, x.LatestPushTime x.QuestionType, x.LatestPushError
}); });
} }
private async Task DoAddAsync(TrackPushEvent @event, private async Task DoAddAsync(TrackPushEvent @event,
TrackPushContentConfigDto config, TrackPushRecordIndex log) TrackPushContentConfigDto config, TrackPushRecordIndex log)
{ {
var track = new var track = new TrackItem
{ {
// 推真实的发生地和发生时间(时间是计算后的) // 推真实的发生地和发生时间(时间是计算后的)
location = @event.TrackPlace, Location = @event.TrackPlace,
date = @event.TrackTime.AddHours( Date = @event.TrackTime.AddHours(
config.TrackTimeZone ?? @event.TrackTimeZone - @event.TrackTimeZone), config.TrackTimeZone ?? @event.TrackTimeZone - @event.TrackTimeZone),
timeZone = config.TrackTimeZone ?? @event.TrackTimeZone, TimeZone = config.TrackTimeZone ?? @event.TrackTimeZone,
description = config.TrackEnContentValue, Description = config.TrackEnContentValue,
description_cn = config.TrackContentValue, DescriptionCn = config.TrackContentValue,
code = config.TrackContentCodeValue, Code = config.TrackContentCodeValue,
status = config.TrackStatusValue, Status = config.TrackStatusValue,
extra = config.ExpandFieldsValue Extra = config.ExpandFieldsValue
}; };
JObject body = JObject.FromObject(new var body = new TrackPushInput()
{ {
orderNo = @event.OrderNo, OrderNo = @event.OrderNo,
data = new[] { track } };
}); body.Data.Add(track);
if (config.IsAllPush) if (config.IsAllPush)
{ {
var history = await _trackPushRecordsRepository.GetLatestTrackPushRecordAsync(@event.OrderId); var history = await _trackPushRecordsRepository.GetLatestTrackPushRecordAsync(@event.OrderId);
if (history != default) if (history != default)
{ {
body = JObject.Parse(history.PushContent); body = JsonConvert.DeserializeObject<TrackPushInput>(history.PushContent);
((JArray)body["data"]!).Add(JObject.FromObject(track)); body!.Data.Add(track);
} }
} }
@ -178,6 +189,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
config.ServiceProviderCode, body); config.ServiceProviderCode, body);
log.PushContent = body.ToJson(); log.PushContent = body.ToJson();
log.IsSuccess = res.Code == InterfaceRelayConst.SuccessCode; log.IsSuccess = res.Code == InterfaceRelayConst.SuccessCode;
log.RequestId = res.RequestId; log.RequestId = res.RequestId;
log.Message = res.Msg; log.Message = res.Msg;

View File

@ -9,6 +9,7 @@ using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Helpers; using SJZY.Track.Application.Helpers;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Consts;
using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Enums;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -20,13 +21,16 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
private readonly ICapPublisher _capPublisher; private readonly ICapPublisher _capPublisher;
private readonly ITrackPullCacheService _trackPullCacheService; private readonly ITrackPullCacheService _trackPullCacheService;
private readonly ITrackDetailsRepository _trackDetailsRepository;
public TrackRefreshEventHandler(IOrderRepository orderRepository, public TrackRefreshEventHandler(IOrderRepository orderRepository,
ICapPublisher capPublisher, ITrackPullCacheService trackPullCacheService) ICapPublisher capPublisher, ITrackPullCacheService trackPullCacheService,
ITrackDetailsRepository trackDetailsRepository)
{ {
_orderRepository = orderRepository; _orderRepository = orderRepository;
_capPublisher = capPublisher; _capPublisher = capPublisher;
_trackPullCacheService = trackPullCacheService; _trackPullCacheService = trackPullCacheService;
_trackDetailsRepository = trackDetailsRepository;
} }
[CapSubscribe(GlobalConst.TrackRefreshSubscribe, Group = GlobalConst.TrackRefreshSubscribe)] [CapSubscribe(GlobalConst.TrackRefreshSubscribe, Group = GlobalConst.TrackRefreshSubscribe)]
@ -89,15 +93,19 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe
await HandleTrackAsync(item, paramWithContentConfig, context); await HandleTrackAsync(item, paramWithContentConfig, context);
} }
} }
else if (orderToken is JObject) else if (trackToken is JObject)
{ {
await HandleTrackAsync(orderToken, paramWithContentConfig, context); await HandleTrackAsync(trackToken, paramWithContentConfig, context);
} }
} }
private async Task HandleTrackAsync(JToken trackToken, TrackPullParamWithContentConfigDto paramWithContentConfig, private async Task HandleTrackAsync(JToken trackToken, TrackPullParamWithContentConfigDto paramWithContentConfig,
TrackRefreshContext context) TrackRefreshContext context)
{ {
var originTrackData = JsonConvert.SerializeObject(trackToken);
// 如果已经存在一模一样的报文了说明处理过了,直接return
if (await _trackDetailsRepository.AnyAsync(context.OrderId, originTrackData)) return;
var paramConfig = paramWithContentConfig.ParamConfig; var paramConfig = paramWithContentConfig.ParamConfig;
var contentConfigs = paramWithContentConfig.ContentConfigs; var contentConfigs = paramWithContentConfig.ContentConfigs;
TrackPullContentConfigDto? matchedContentConfig = null; TrackPullContentConfigDto? matchedContentConfig = null;
@ -213,18 +221,32 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe
// 新增/更新轨迹 // 新增/更新轨迹
var trackUpsertEvent = new TrackUpsertEvent var trackUpsertEvent = new TrackUpsertEvent
{
OrderIdentifiers = new[]
{
new OrderIdentifier
{ {
OrderId = context.OrderId, OrderId = context.OrderId,
OrderType = context.OrderType,
OrderNo = context.OrderNo, OrderNo = context.OrderNo,
OrderType = context.OrderType
}
},
TrackRefreshData = new TrackRefreshStruct
{
ServiceProviderName = context.ServiceProviderName, ServiceProviderName = context.ServiceProviderName,
OriginTrackData = originTrackData,
IsCompleted = matchedContentConfig.IsCompleted, IsCompleted = matchedContentConfig.IsCompleted,
OriginTrackContent = paramConfig.TrackContentName != null
? trackToken[paramConfig.TrackContentName]?.Value<string>()
: GlobalConst.EmptyString
},
SubSystemId = context.SubSystemId, SubSystemId = context.SubSystemId,
TrackCode = matchedContentConfig.TrackContentCode, TrackCode = matchedContentConfig.TrackContentCode,
TrackPlace = trackPlace ?? GlobalConst.EmptyString, TrackPlace = trackPlace ?? GlobalConst.EmptyString,
TrackTime = trackTime ?? DateTime.Now, TrackTime = trackTime ?? DateTime.Now,
TrackTimeZone = trackTimeZone ?? matchedContentConfig.TrackTimeZoneValue ?? 8 TrackTimeZone = trackTimeZone ?? matchedContentConfig.TrackTimeZoneValue ?? 8
}; };
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, trackUpsertEvent);
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent);
} }
} }

View File

@ -26,20 +26,52 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
_trackDetailsRepository = trackDetailsRepository; _trackDetailsRepository = trackDetailsRepository;
} }
[CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)]
[CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)]
public async Task ConsumerAsync(TrackUpsertEvent @event) public async Task ConsumerAsync(TrackUpsertEvent @event)
{ {
if (@event.Visited.Contains(@event.OrderId)) var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray();
var dup = @event.Visited.Intersect(orderIds).ToArray();
if (dup.Any())
{ {
LogHelper.Error($"轨迹订单循环依赖预警:{@event.Visited.JoinAsString(",")}"); LogHelper.Error($"删除轨迹订单时,发现循环依赖:{dup.JoinAsString(",")}");
return; return;
} }
await HandleTrackAsync(@event);
// 根据订单关联关系异步向下刷(异步)
var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(orderIds);
foreach (var order in @event.OrderIdentifiers)
{
// 理论上小包在这不会分组
foreach (var group in linkedOrders.Where(x => x.OrderId == order.OrderId)
.GroupBy(x => x.SubSystemId))
{
var nextEvent = @event.DeepCopy();
nextEvent.Visited.AddRange(orderIds);
nextEvent.SubSystemId = group.Key;
nextEvent.OrderIdentifiers = group.Select(x => new OrderIdentifier
{
OrderId = x.OrderId,
OrderNo = x.OrderNo,
OrderType = x.OrderType
}).ToArray();
nextEvent.TrackRefreshData = new TrackRefreshStruct
{
ServiceProviderName = @event.TrackRefreshData.ServiceProviderName,
OriginTrackContent = @event.TrackRefreshData.OriginTrackContent,
OriginTrackData = @event.TrackRefreshData.OriginTrackData,
// tips:一定要重置为false,父级订单的完成不会使得关联订单完成,关联单也必须由刷新来完成或手动设置完成!!
IsCompleted = false
};
// 不同子系统需要做内容映射 // 不同子系统需要做内容映射
if (@event.UpSubSystemId != 0 && @event.UpSubSystemId != @event.SubSystemId) if (@event.SubSystemId != nextEvent.SubSystemId)
{ {
var mapCode = (await _provideQueries var mapCode = (await _provideQueries
.MapTrackCodesAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCode)) .MapTrackCodesAsync(@event.SubSystemId, nextEvent.SubSystemId, @event.TrackCode))
.FirstOrDefault(); .FirstOrDefault();
if (mapCode == default) if (mapCode == default)
@ -51,7 +83,21 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
@event.TrackCode = mapCode; @event.TrackCode = mapCode;
} }
var track = await _trackDetailsRepository.GetFirstOrDefaultAsync(@event.OrderId, @event.TrackCode); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, nextEvent);
}
}
}
private async Task HandleTrackAsync(TrackUpsertEvent @event)
{
var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray();
var tracks = await _trackDetailsRepository.GetListAsync(orderIds, @event.TrackCode);
var insertTracks = new List<TrackDetailsIndex>();
foreach (var order in @event.OrderIdentifiers)
{
var track = tracks.FirstOrDefault(x => x.OrderId == order.OrderId);
if (@event.IsAdd != null) if (@event.IsAdd != null)
{ {
@ -60,9 +106,54 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
} }
// step1、upsert es轨迹 // step1、upsert es轨迹
track = await UpsertTrackAsync(track, @event); if (track == default)
{
track = new TrackDetailsIndex
{
IndexName = $"{GlobalConst.TrackIndex}-{DateTime.Now:yyyy.MM.dd}",
OrderId = order.OrderId,
OrderNo = order.OrderNo,
OrderType = order.OrderType,
TrackCode = @event.TrackCode,
TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone,
ServiceProviderName = @event.TrackRefreshData.ServiceProviderName,
OriginTrackContent = @event.TrackRefreshData.OriginTrackContent,
OriginTrackData = @event.TrackRefreshData.OriginTrackData,
IsCanDelete = false,
CreateUser = @event.OperationMan ?? GlobalConst.SystemUser,
CreateTime = DateTime.Now
};
if (track == null) return; // 模板没配该轨迹代码,不再继续 //todo:可以优化?
// 根据轨迹code在订单模板内容中寻找匹配的
var trackContent = await _provideQueries.MatchTrackContentAsync(order.OrderId, @event.TrackCode);
if (trackContent == default)
{
// 订单所绑定的模板,没有一条内容可以匹配发生的轨迹
continue;
}
track.TrackStatus = trackContent.Status;
track.TrackCode = trackContent.TrackCode;
track.TrackContent = trackContent.Content;
track.TrackEnContent = trackContent.EnContent;
track.IsCanDelete = trackContent.IsCanDelete;
track.ZeroTrackTime = track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
insertTracks.Add(track);
}
else
{
track.TrackPlace = @event.TrackPlace;
track.TrackTime = @event.TrackTime;
track.TrackTimeZone = @event.TrackTimeZone;
track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser;
track.UpdateTime = DateTime.Now;
await _trackDetailsRepository.UpdateAsync(track);
}
// step2、触发轨迹推送事件(异步) // step2、触发轨迹推送事件(异步)
var trackPushEvent = new TrackPushEvent var trackPushEvent = new TrackPushEvent
@ -84,8 +175,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe, await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe,
new TrackChangeAfterUpdateOrderEvent new TrackChangeAfterUpdateOrderEvent
{ {
OrderId = track.OrderId, OrderIds = new[] { track.OrderId },
IsCompleted = @event.IsCompleted, IsCompleted = @event.TrackRefreshData.IsCompleted,
TrackCode = track.TrackCode, TrackCode = track.TrackCode,
TrackContent = track.TrackContent, TrackContent = track.TrackContent,
TrackEnContent = track.TrackEnContent, TrackEnContent = track.TrackEnContent,
@ -93,76 +184,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackTime = track.TrackTime, TrackTime = track.TrackTime,
TrackTimeZone = track.TrackTimeZone TrackTimeZone = track.TrackTimeZone
}); });
// step4、根据订单关联关系异步向下刷(异步)
var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderId);
foreach (var linkedOrder in linkedOrders)
{
var nextEvent = @event.DeepCopy();
nextEvent.Visited.Add(@event.OrderId);
// tips:一定要重置为false,父级订单的完成不会使得关联订单完成,关联单也必须由刷新来完成或手动设置完成!!
nextEvent.IsCompleted = false; // 能够使得轨迹IsCompleted为true的点,全局只有一个:轨迹刷新
nextEvent.OrderId = linkedOrder.OrderId;
nextEvent.OrderType = linkedOrder.OrderType;
nextEvent.OrderNo = linkedOrder.OrderNo;
nextEvent.SubSystemId = linkedOrder.SubSystemId;
nextEvent.UpSubSystemId = @event.SubSystemId;
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, nextEvent);
}
} }
/// <summary> await _trackDetailsRepository.AddManyAsync(insertTracks);
/// 不存在则新增轨迹,存在则更新
/// </summary>
/// <param name="track"></param>
/// <param name="event"></param>
private async Task<TrackDetailsIndex?> UpsertTrackAsync(TrackDetailsIndex? track, TrackUpsertEvent @event)
{
if (track == default)
{
track = new TrackDetailsIndex
{
IndexName = $"{GlobalConst.TrackIndex}-{DateTime.Now:yyyy.MM.dd}",
OrderId = @event.OrderId,
OrderNo = @event.OrderNo,
OrderType = @event.OrderType,
TrackCode = @event.TrackCode,
TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone,
ServiceProviderName = @event.ServiceProviderName,
IsCanDelete = false,
CreateUser = @event.OperationMan ?? GlobalConst.SystemUser,
CreateTime = DateTime.Now
};
//todo:可以优化
// 根据轨迹code在订单模板内容中寻找匹配的
var trackContent = await _provideQueries.MatchTrackContentAsync(@event.OrderId, @event.TrackCode);
if (trackContent == default)
{
// 订单所绑定的模板,没有一条内容可以匹配发生的轨迹
return null;
}
track.TrackStatus = trackContent.Status;
track.TrackCode = trackContent.TrackCode;
track.TrackContent = trackContent.Content;
track.TrackEnContent = trackContent.EnContent;
track.IsCanDelete = trackContent.IsCanDelete;
track.ZeroTrackTime = track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
}
else
{
track.TrackPlace = @event.TrackPlace;
track.TrackTime = @event.TrackTime;
track.TrackTimeZone = @event.TrackTimeZone;
track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser;
track.UpdateTime = DateTime.Now;
}
await _trackDetailsRepository.UpsertAsync(track);
return track;
} }
} }

View File

@ -12,7 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SJZY.InterfaceRelay.Application.Contracts" Version="7.1.8"/> <PackageReference Include="SJZY.InterfaceRelay.Application.Contracts" Version="7.1.9"/>
<PackageReference Include="Volo.Abp.Http.Client" Version="7.0.2" /> <PackageReference Include="Volo.Abp.Http.Client" Version="7.0.2" />
<PackageReference Include="Volo.Abp.FluentValidation" Version="7.0.2" /> <PackageReference Include="Volo.Abp.FluentValidation" Version="7.0.2" />
<PackageReference Include="SJZY.UserCenter.HttpApi" Version="3.0.3-alpha8" /> <PackageReference Include="SJZY.UserCenter.HttpApi" Version="3.0.3-alpha8" />

View File

@ -2,6 +2,7 @@
using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Consts;
using SJZY.Track.Domain.Queries; using SJZY.Track.Domain.Queries;
@ -14,6 +15,7 @@ public partial class OrderService
{ {
private readonly IBasicQuery<OrderLinkEntity> _orderLinkQuery; private readonly IBasicQuery<OrderLinkEntity> _orderLinkQuery;
private readonly ICapPublisher _capPublisher; private readonly ICapPublisher _capPublisher;
private readonly ITrackDetailsRepository _trackDetailsRepository;
/// <summary> /// <summary>
/// 关联、解除关联订单 /// 关联、解除关联订单
@ -52,23 +54,12 @@ public partial class OrderService
if (!input.IsLink) return await UnLinkOrderAsync(input); if (!input.IsLink) return await UnLinkOrderAsync(input);
// 关联订单 // 关联订单
var linkedOrders = await DoLinkOrderAsync(input, order.Id); await DoLinkOrderAsync(input, order.Id);
// 补轨迹
if (linkedOrders.Count > 0)
{
await _capPublisher.PublishAsync(GlobalConst.OrderLinkAfterFillTrack, new OrderLinkAfterFillTrackEvent
{
OrderId = order.Id,
SubSystemId = order.SubSystemId,
LinkedOrders = linkedOrders,
});
}
return new UnifyResultDto(true, true); return new UnifyResultDto(true, true);
} }
private async Task<List<LinkedOrder>> DoLinkOrderAsync(LinkOrderInput input, int orderId) private async Task DoLinkOrderAsync(LinkOrderInput input, int orderId)
{ {
// 获取已关联的订单 // 获取已关联的订单
var linkOrderNos = await _orderLinkQuery.GetListAsync(x => var linkOrderNos = await _orderLinkQuery.GetListAsync(x =>
@ -81,9 +72,9 @@ public partial class OrderService
// 过滤掉不存在的订单 // 过滤掉不存在的订单
var canLinkOrders = await _orderRepository.GetListAsync(x => var canLinkOrders = await _orderRepository.GetListAsync(x =>
x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo),
x => new { x.Id, x.OrderNo, x.SubSystemId }); x => new { x.Id, x.OrderNo, x.OrderType, x.SubSystemId });
if (canLinkOrders.Count == 0) return new List<LinkedOrder>(); if (canLinkOrders.Count == 0) return;
await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity
{ {
@ -95,13 +86,32 @@ public partial class OrderService
LinkOrderType = input.LinkOrderType LinkOrderType = input.LinkOrderType
}).ToList()); }).ToList());
return canLinkOrders.Select(x => new LinkedOrder var tracks = await _trackDetailsRepository.GetListAsync(orderId);
// 补轨迹
foreach (var group in canLinkOrders.GroupBy(x => x.SubSystemId))
{
foreach (var track in tracks)
{
var fillTrackEvent = new TrackUpsertEvent
{
SubSystemId = group.Key,
OrderIdentifiers = group.Select(x => new OrderIdentifier
{ {
SubSystemId = x.SubSystemId,
OrderId = x.Id, OrderId = x.Id,
OrderNo = x.OrderNo, OrderNo = x.OrderNo,
OrderType = input.LinkOrderType OrderType = x.OrderType
}).ToList(); }).ToArray(),
TrackCode = track.TrackCode,
TrackPlace = track.TrackPlace,
TrackTime = track.TrackTime,
TrackTimeZone = track.TrackTimeZone,
IsAdd = true
};
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, fillTrackEvent);
}
}
} }
private async Task<UnifyResultDto> UnLinkOrderAsync(LinkOrderInput input) private async Task<UnifyResultDto> UnLinkOrderAsync(LinkOrderInput input)

View File

@ -2,6 +2,7 @@
using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Queries; using SJZY.Track.Domain.Queries;
using SJZY.UserCenter.HttpApi.Services; using SJZY.UserCenter.HttpApi.Services;
@ -17,9 +18,10 @@ public partial class OrderService : ApplicationService, IOrderService
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
public OrderService(IOrderRepository orderRepository, IBasicQuery<OrderLinkEntity> orderLinkQuery, public OrderService(IOrderRepository orderRepository, IBasicQuery<OrderLinkEntity> orderLinkQuery,
ICapPublisher capPublisher) ICapPublisher capPublisher, ITrackDetailsRepository trackDetailsRepository)
{ {
_orderRepository = orderRepository; _orderRepository = orderRepository;
_trackDetailsRepository = trackDetailsRepository;
_capPublisher = capPublisher; _capPublisher = capPublisher;
_orderLinkQuery = orderLinkQuery; _orderLinkQuery = orderLinkQuery;
} }

View File

@ -64,7 +64,7 @@ public class TrackPullService : ApplicationService
var attach = Base64Helper.SerializeObject(group.Key); var attach = Base64Helper.SerializeObject(group.Key);
// 批量获取轨迹 // 批量获取轨迹
await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( var _ = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
"A012", serviceProviderCode, data, GlobalConst.TrackRefreshSubscribe, attach); "A012", serviceProviderCode, data, GlobalConst.TrackRefreshSubscribe, attach);
} }

View File

@ -0,0 +1,45 @@
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Dtos.TrackPush;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.ObjectMapping;
namespace SJZY.Track.Application.Services.ProvideServices
{
/// <summary>
/// 轨迹推送配置服务
/// </summary>
[ApiExplorerSettings(GroupName = "提供接口")]
[Route("/ProviderService")]
public class TrackPushConfigService : ApplicationService, ITrackPushConfigService
{
private readonly ITrackPushConfigRepository _trackPushConfigRepository;
public TrackPushConfigService(
ITrackPushConfigRepository trackPushConfigRepository
)
{
_trackPushConfigRepository = trackPushConfigRepository;
}
/// <summary>
/// 查询轨迹推送配置关系
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("Track/QueryTrackPullMappings")]
public async Task<UnifyResultDto> QueryTrackPullMappingsAsync(QueryTrackPullMappingsInput input)
{
var vo = ObjectMapper.Map<QueryTrackPullMappingsInput, QueryTrackPullMappingsInputVO>(input);
var result = await _trackPushConfigRepository.QueryTrackPullMappingsAsync(vo);
var output = ObjectMapper.Map<List<QueryTrackPullMappingsInfoVO>, List<QueryTrackPullMappingsInfo>>(result);
return new UnifyResultDto(true, output, "操作成功");
}
}
}

View File

@ -17,7 +17,7 @@ public partial class TrackService
/// <returns></returns> /// <returns></returns>
/// <exception cref="BusinessException"></exception> /// <exception cref="BusinessException"></exception>
[HttpPost("Track/Query")] [HttpPost("Track/Query")]
public async Task<List<GetTrackOutput>> QueryAsync(GetTrackInput input) public async Task<UnifyResultDto> QueryAsync(GetTrackInput input)
{ {
if (input.OrderNos.Count > 500) if (input.OrderNos.Count > 500)
{ {
@ -39,6 +39,7 @@ public partial class TrackService
Code = x.TrackCode, Code = x.TrackCode,
Status = x.TrackStatus, Status = x.TrackStatus,
Content = x.TrackContent, Content = x.TrackContent,
OriginContent = x.OriginTrackContent,
Location = x.TrackPlace, Location = x.TrackPlace,
Time = x.TrackTime.AddHours(input.TimeZone ?? 8 - x.TrackTimeZone), Time = x.TrackTime.AddHours(input.TimeZone ?? 8 - x.TrackTimeZone),
TimeZone = input.TimeZone ?? 8 TimeZone = input.TimeZone ?? 8
@ -49,25 +50,16 @@ public partial class TrackService
await TrackDetailSort(res, input); await TrackDetailSort(res, input);
return res; return new UnifyResultDto(true, res, "操作成功");
} }
private async Task TrackDetailSort(List<GetTrackOutput> list, GetTrackInput input) private async Task TrackDetailSort(List<GetTrackOutput> list, GetTrackInput input)
{ {
switch (input.SortMethod)
{
case SortMethod.ByTrackTime:
// tips:quick-sort 直接修改原list
list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time)));
break;
case SortMethod.ByTrackTimeDesc:
list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time)));
break;
case SortMethod.ByTemplate:
var orderTemplates = await _provideQueries var orderTemplates = await _provideQueries
.GetOrderTemplateLinksAsync(input.OrderType, input.OrderNos); .GetOrderTemplateLinksAsync(input.OrderType, input.OrderNos);
var distinctTemplateIds = orderTemplates.Select(x => x.TemplateId).Distinct().ToList(); var distinctTemplateIds = orderTemplates.Select(x => x.TemplateId).Distinct().ToList();
var templateContent = await _provideQueries.GetOrderedTrackCodesAsync(distinctTemplateIds); var templateContent = await _provideQueries.GetOrderedTrackCodesAsync(distinctTemplateIds);
list.ForEach(item => list.ForEach(item =>
{ {
var codes = new List<string>(); var codes = new List<string>();
@ -85,9 +77,32 @@ public partial class TrackService
.OrderBy(x => codes.IndexOf(x.Code)) // 按照在模板内容的位置排序 .OrderBy(x => codes.IndexOf(x.Code)) // 按照在模板内容的位置排序
.ToList(); .ToList();
}); });
switch (input.SortMethod)
{
case SortMethod.ByTrackTime:
// tips:quick-sort 直接修改原list
list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time)));
break;
case SortMethod.ByTrackTimeDesc:
list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time)));
break;
case SortMethod.ByTemplate:
break; break;
default: default:
throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式"); throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式");
} }
// 显示原轨迹
list.ForEach(item =>
{
item.TrackDetails.ForEach(track =>
{
if (templateContent.First(x => x.Code == track.Code).ShowOrigin)
{
track.Content = track.OriginContent;
}
});
});
} }
} }

View File

@ -43,7 +43,7 @@ public partial class TrackService : ApplicationService, ITrackService
var order = await _orderRepository.GetFirstAsync(x => var order = await _orderRepository.GetFirstAsync(x =>
x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new
{ {
x.Id, x.SubSystemId x.Id, x.SubSystemId, x.OrderNo, x.OrderType
}); });
if (order == default) if (order == default)
{ {
@ -52,8 +52,16 @@ public partial class TrackService : ApplicationService, ITrackService
// 新增/更新轨迹 // 新增/更新轨迹
var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(input); var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(input);
@event.OrderId = order.Id;
@event.SubSystemId = order.SubSystemId; @event.SubSystemId = order.SubSystemId;
@event.OrderIdentifiers = new[]
{
new OrderIdentifier
{
OrderId = order.Id,
OrderNo = order.OrderNo,
OrderType = order.OrderType
}
};
@event.OperationMan = CurrentUserRequest.CurrentUser.Name; @event.OperationMan = CurrentUserRequest.CurrentUser.Name;
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
return new UnifyResultDto(true, true); return new UnifyResultDto(true, true);
@ -80,25 +88,29 @@ public partial class TrackService : ApplicationService, ITrackService
x.Id, x.OrderNo, x.SubSystemId x.Id, x.OrderNo, x.SubSystemId
}); });
foreach (var order in orders) foreach (var group in orders.GroupBy(x => x.SubSystemId))
{ {
// 新增/更新轨迹 // 新增/更新轨迹
var @event = new TrackUpsertEvent var @event = new TrackUpsertEvent
{ {
SubSystemId = group.Key,
OrderIdentifiers = group.Select(order => new OrderIdentifier
{
OrderId = order.Id,
OrderNo = order.OrderNo,
OrderType = input.OrderType
}).ToArray(),
IsAdd = input.IsAdd, IsAdd = input.IsAdd,
TrackCode = input.TrackCode, TrackCode = input.TrackCode,
TrackPlace = input.TrackPlace, TrackPlace = input.TrackPlace,
TrackTime = input.TrackTime!.Value, TrackTime = input.TrackTime!.Value,
TrackTimeZone = input.TrackTimeZone!.Value, TrackTimeZone = input.TrackTimeZone!.Value,
OrderType = input.OrderType,
OrderNo = order.OrderNo,
OrderId = order.Id,
SubSystemId = order.SubSystemId,
OperationMan = CurrentUserRequest.CurrentUser.Name OperationMan = CurrentUserRequest.CurrentUser.Name
}; };
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
} }
return new UnifyResultDto(true, true); return new UnifyResultDto(true, true);
} }
@ -132,7 +144,7 @@ public partial class TrackService : ApplicationService, ITrackService
// 删除轨迹 // 删除轨迹
var @event = new TrackDeleteEvent var @event = new TrackDeleteEvent
{ {
OrderId = order.Id, OrderIds = new[] { order.Id },
TrackCodes = codes.Select(x => x.TrackCode).ToList(), TrackCodes = codes.Select(x => x.TrackCode).ToList(),
SubSystemId = order.SubSystemId, SubSystemId = order.SubSystemId,
OperationMan = CurrentUserRequest.CurrentUser.Name OperationMan = CurrentUserRequest.CurrentUser.Name
@ -173,7 +185,7 @@ public partial class TrackService : ApplicationService, ITrackService
{ {
var @event = new TrackDeleteEvent var @event = new TrackDeleteEvent
{ {
OrderId = group.Key, OrderIds = group.Select(x => x.OrderId).ToArray(),
TrackCodes = codes.Select(x => x.TrackCode).ToList(), TrackCodes = codes.Select(x => x.TrackCode).ToList(),
SubSystemId = orders.First(x => x.Id == group.Key).SubSystemId, SubSystemId = orders.First(x => x.Id == group.Key).SubSystemId,
OperationMan = CurrentUserRequest.CurrentUser.Name OperationMan = CurrentUserRequest.CurrentUser.Name

View File

@ -59,6 +59,8 @@ public class TrackContentService : ApplicationService
} }
var dto = ObjectMapper.Map<GetTrackContentDetailVO, GetTrackContentDetailDto>(detailInfo); var dto = ObjectMapper.Map<GetTrackContentDetailVO, GetTrackContentDetailDto>(detailInfo);
if (dto.TrackFlagId == 0) dto.TrackFlagId = null;
return new UnifyResultDto<GetTrackContentDetailDto>("200", "", dto); return new UnifyResultDto<GetTrackContentDetailDto>("200", "", dto);
} }

View File

@ -160,8 +160,20 @@ public class TrackOrderService : ApplicationService
/// <returns></returns> /// <returns></returns>
/// <param name="orderId">订单id</param> /// <param name="orderId">订单id</param>
[HttpGet("GetTrackPushRecords")] [HttpGet("GetTrackPushRecords")]
public async Task<List<TrackPushRecordIndex>> GetTrackPushRecordsAsync(int orderId) public async Task<List<TrackPushRecordOutput>> GetTrackPushRecordsAsync(int orderId)
{ {
return await _trackPushRecordsRepository.GetTrackPushRecordsAsync(orderId); var records = await _trackPushRecordsRepository.GetTrackPushRecordsAsync(orderId);
var res = ObjectMapper.Map<List<TrackPushRecordIndex>, List<TrackPushRecordOutput>>(records);
res.ForEach(x =>
{
int hours = (int)x.TrackTimeZone; // 提取整数部分作为小时
int minutes = (int)((x.TrackTimeZone - hours) * 60); // 将小数部分乘以 60 转换为分钟
x.TrackGTMTimeZone =
$"GTM {(x.TrackTimeZone >= 0 ? "+" : "-")}{new TimeSpan(hours, minutes, 0).ToString().RemovePostFix(":00")}";
});
return res;
} }
} }

View File

@ -1,5 +1,4 @@
using System.Linq.Expressions; using SJZY.Expand.ABP.Core;
using SJZY.Expand.ABP.Core;
using SJZY.Track.Application.Contract.Dtos.TrackPush; using SJZY.Track.Application.Contract.Dtos.TrackPush;
using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
@ -22,11 +21,25 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
public async Task<List<TrackPushContentConfigDto>?> GetPushContentConfigsAsync(int subSystemId, int customId) public async Task<List<TrackPushContentConfigDto>?> GetPushContentConfigsAsync(int subSystemId, int customId)
{ {
var data = await RedisHelper.Client.GetAsync<List<TrackPushContentConfigDto>>( var exists = await RedisHelper.Client.ExistsAsync(TrackPushContentKey(subSystemId, customId));
if (exists)
{
return await RedisHelper.Client.GetAsync<List<TrackPushContentConfigDto>>(
TrackPushContentKey(subSystemId, customId)); TrackPushContentKey(subSystemId, customId));
}
data ??= await SetPushContentConfigsAsync(subSystemId: subSystemId, customId: customId); return await SetPushContentConfigsAsync(subSystemId, customId);
}
public async Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int subSystemId, int customId)
{
// maybe is null
var data = await DoGetPushContentConfigsAsync(subSystemId, customId);
var ttl = 3 * 24 * 60 * 60;
if (data == null) ttl = 5;
// ttl 3days
await RedisHelper.Client.SetAsync(TrackPushContentKey(subSystemId, customId),
data, ttl);
return data; return data;
} }
@ -55,26 +68,26 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
// find swap // find swap
cache.FirstOrDefault(x => x.TrackCode == cache[idx + 1].SwapTrackCode); cache.FirstOrDefault(x => x.TrackCode == cache[idx + 1].SwapTrackCode);
return matched != null && matched.TrackCode == trackCode && matched.IsAutoPush ? matched : default; return matched != null && matched.TrackCode == trackCode ? matched : default;
} }
public async Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int? id = null, private async Task<List<TrackPushContentConfigDto>?> DoGetPushContentConfigsAsync(int subSystemId, int customId)
int? subSystemId = null,
int? customId = null)
{ {
Expression<Func<TrackPushConfigEntity, bool>> exp = x => true; var trackPushConfig = await _trackPushConfigRepository.GetFirstAsync(
if (id.HasValue) exp = x => x.Id == id; x => x.SubSystemId == subSystemId && x.CustomId == customId, x => new
else if (subSystemId.HasValue && customId.HasValue)
exp = x => x.SubSystemId == subSystemId && x.CustomId == customId;
var trackPushConfig = await _trackPushConfigRepository.GetFirstAsync(exp, x => new
{ {
x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId
}); });
if (trackPushConfig == null) return null; if (trackPushConfig == null)
{
return null;
}
var trackPushContentList = await _trackPushConfigRepository.GetContentListAsync(trackPushConfig.Id); var trackPushContentList = await _trackPushConfigRepository.GetContentListAsync(trackPushConfig.Id);
if (trackPushContentList.Count == 0) return null; if (trackPushContentList.Count == 0)
{
return null;
}
// tips:hot path,auto mapper性能不如原生 // tips:hot path,auto mapper性能不如原生
var res = trackPushContentList.Select(item => new TrackPushContentConfigDto var res = trackPushContentList.Select(item => new TrackPushContentConfigDto
@ -95,9 +108,6 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
ExpandFieldsValue = item.ExpandFieldsValue, ExpandFieldsValue = item.ExpandFieldsValue,
}).ToList(); }).ToList();
await RedisHelper.Client.SetAsync(TrackPushContentKey(trackPushConfig.SubSystemId, trackPushConfig.CustomId),
res);
return res; return res;
} }
} }

View File

@ -95,12 +95,17 @@ public class TrackPushService : ApplicationService
throw new BusinessException(message: _stringLocalizer["IsTrackPushConfigAny"]); throw new BusinessException(message: _stringLocalizer["IsTrackPushConfigAny"]);
} }
using var ts = TransactionScopeHelper.Create();
switch (input.Options) switch (input.Options)
{ {
case OptionTypeNoNull.新增: case OptionTypeNoNull.新增:
{ {
var trackPushEntity = ObjectMapper.Map<EditTrackPushConfigInput, TrackPushConfigEntity>(input); var trackPushEntity = ObjectMapper.Map<EditTrackPushConfigInput, TrackPushConfigEntity>(input);
await _trackPushConfigRepository.InsertReturnIdentityAsync(trackPushEntity); await _trackPushConfigRepository.InsertReturnIdentityAsync(trackPushEntity);
await _trackPushCacheService.SetPushContentConfigsAsync(trackPushEntity.SubSystemId,
trackPushEntity.CustomId);
} }
break; break;
@ -111,21 +116,19 @@ public class TrackPushService : ApplicationService
ObjectMapper.Map(input, oldTrackPushEntity); ObjectMapper.Map(input, oldTrackPushEntity);
await _trackPushConfigRepository.UpdateAsync(oldTrackPushEntity); await _trackPushConfigRepository.UpdateAsync(oldTrackPushEntity);
await _trackPushCacheService.SetPushContentConfigsAsync(oldTrackPushEntity.SubSystemId,
if (input.IsAutoPush!.Value) await _trackPushCacheService.SetPushContentConfigsAsync(input.Id); oldTrackPushEntity.CustomId);
} }
break; break;
case OptionTypeNoNull.删除: case OptionTypeNoNull.删除:
{ {
_ = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? var entity = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
throw new BusinessException(message: _stringLocalizer["NotFindData"]); throw new BusinessException(message: _stringLocalizer["NotFindData"]);
using var ts = TransactionScopeHelper.Create();
await _trackPushConfigRepository.SoftDeleteAsync(x => x.Id == input.Id); await _trackPushConfigRepository.SoftDeleteAsync(x => x.Id == input.Id);
await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.TrackPushConfigId == input.Id); await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.TrackPushConfigId == input.Id);
await _trackPushCacheService.SetPushContentConfigsAsync(entity.SubSystemId, entity.CustomId);
ts.Complete();
} }
break; break;
@ -134,6 +137,7 @@ public class TrackPushService : ApplicationService
nameof(EditTrackPushConfigInput.Options)]); nameof(EditTrackPushConfigInput.Options)]);
} }
ts.Complete();
return true; return true;
} }
@ -172,6 +176,10 @@ public class TrackPushService : ApplicationService
throw new BusinessException(message: _stringLocalizer["IsTrackPushEnContentValueAny"]); throw new BusinessException(message: _stringLocalizer["IsTrackPushEnContentValueAny"]);
} }
var trackPushConfigId = input.TrackPushConfigId;
using var ts = TransactionScopeHelper.Create();
switch (input.Options) switch (input.Options)
{ {
case OptionTypeNoNull.新增: case OptionTypeNoNull.新增:
@ -181,10 +189,7 @@ public class TrackPushService : ApplicationService
var entity = ObjectMapper.Map<EditTrackPushContentInput, TrackPushContentConfigEntity>(input); var entity = ObjectMapper.Map<EditTrackPushContentInput, TrackPushContentConfigEntity>(input);
entity.Sort = maxSort + 1; entity.Sort = maxSort + 1;
await _trackPushConfigRepository.InsertContentAsync(entity); await _trackPushConfigRepository.InsertContentAsync(entity);
await _trackPushCacheService.SetPushContentConfigsAsync(input.TrackPushConfigId);
break; break;
} }
@ -194,10 +199,7 @@ public class TrackPushService : ApplicationService
throw new BusinessException(message: _stringLocalizer["NotFindData"]); throw new BusinessException(message: _stringLocalizer["NotFindData"]);
ObjectMapper.Map(input, entity); ObjectMapper.Map(input, entity);
await _trackPushConfigRepository.UpdateContentAsync(entity); await _trackPushConfigRepository.UpdateContentAsync(entity);
await _trackPushCacheService.SetPushContentConfigsAsync(entity.TrackPushConfigId);
break; break;
} }
@ -205,18 +207,10 @@ public class TrackPushService : ApplicationService
{ {
var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: _stringLocalizer["NotFindData"]); throw new BusinessException(message: _stringLocalizer["NotFindData"]);
trackPushConfigId = entity.TrackPushConfigId;
using (var ts = TransactionScopeHelper.Create())
{
await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id); await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id);
await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1, await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1,
x => x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort); x => x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort);
ts.Complete();
}
await _trackPushCacheService.SetPushContentConfigsAsync(entity.TrackPushConfigId);
break; break;
} }
@ -225,6 +219,14 @@ public class TrackPushService : ApplicationService
nameof(EditTrackPushContentInput.Options)]); nameof(EditTrackPushContentInput.Options)]);
} }
var pushConfig = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == trackPushConfigId);
if (pushConfig != null)
{
await _trackPushCacheService.SetPushContentConfigsAsync(pushConfig.SubSystemId, pushConfig.CustomId);
}
ts.Complete();
return true; return true;
} }
@ -247,8 +249,19 @@ public class TrackPushService : ApplicationService
if (trackPushContentEntities.Count > 0) if (trackPushContentEntities.Count > 0)
{ {
using var ts = TransactionScopeHelper.Create();
await _trackPushConfigRepository.UpdateContentRangeAsync(trackPushContentEntities); await _trackPushConfigRepository.UpdateContentRangeAsync(trackPushContentEntities);
await _trackPushCacheService.SetPushContentConfigsAsync(trackPushContentEntities[0].TrackPushConfigId);
var pushConfig =
await _trackPushConfigRepository.GetFirstAsync(x =>
x.Id == trackPushContentEntities[0].TrackPushConfigId);
if (pushConfig != null)
{
await _trackPushCacheService.SetPushContentConfigsAsync(pushConfig.SubSystemId, pushConfig.CustomId);
}
ts.Complete();
} }
return true; return true;

View File

@ -1,7 +0,0 @@
namespace SJZY.Track.Application.Services.TrackTemplates
{
public interface ITrackTemplateService
{
}
}

View File

@ -84,12 +84,17 @@ namespace SJZY.Track.Application
configure.UserName = configuration["RabbitMQ:UserName"]!; configure.UserName = configuration["RabbitMQ:UserName"]!;
configure.Password = configuration["RabbitMQ:Password"]!; configure.Password = configuration["RabbitMQ:Password"]!;
configure.Port = configuration.GetValue<int>("RabbitMQ:Port"); configure.Port = configuration.GetValue<int>("RabbitMQ:Port");
configure.BasicQosOptions =
new RabbitMQOptions.BasicQos(configuration.GetValue<ushort>("CAP:PrefetchCount"));
}); });
// options.TopicNamePrefix = "v1"; // options.TopicNamePrefix = "v1";
options.SucceedMessageExpiredAfter = 6 * 60 * 60; options.FailedRetryInterval = configuration.GetValue<int>("CAP:FailedRetryInterval");
options.FailedRetryInterval = 60; options.FailedRetryCount = configuration.GetValue<int>("CAP:FailedRetryCount");
options.FailedRetryCount = 3; options.ConsumerThreadCount = configuration.GetValue<int>("CAP:ConsumerThreadCount");
options.SucceedMessageExpiredAfter = configuration.GetValue<int>("CAP:SucceedMessageExpiredAfter");
options.UseDispatchingPerGroup = true;
options.EnableConsumerPrefetch = true;
options.UseDashboard(dashboardOptions => options.UseDashboard(dashboardOptions =>
{ {
dashboardOptions.PathBase = System.Diagnostics.Debugger.IsAttached dashboardOptions.PathBase = System.Diagnostics.Debugger.IsAttached

View File

@ -38,7 +38,7 @@ public interface IOrderRepository : IBasicRepository<OrderEntity>
/// </summary> /// </summary>
/// <param name="orderId"></param> /// <param name="orderId"></param>
/// <returns></returns> /// <returns></returns>
Task<List<LinkedOrderVO>> GetLinkedOrdersAsync(int orderId); Task<List<LinkedOrderVO>> GetLinkedOrdersAsync(int[] orderId);
/// <summary> /// <summary>
/// 关联订单 /// 关联订单

View File

@ -4,11 +4,18 @@ namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
public interface ITrackDetailsRepository public interface ITrackDetailsRepository
{ {
Task<TrackDetailsIndex?> GetFirstOrDefaultAsync(int orderId, string trackCode); Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode);
Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds);
Task<bool> AnyAsync(int orderId, DateTime trackTime); Task<bool> AnyAsync(int orderId, DateTime trackTime);
Task UpsertAsync(TrackDetailsIndex index); Task<bool> AnyAsync(int orderId, string originTrackData);
Task UpdateAsync(TrackDetailsIndex index);
Task AddManyAsync(List<TrackDetailsIndex> index);
Task<List<TrackDetailsIndex>> GetListAsync(int orderType, List<string> orderNos); Task<List<TrackDetailsIndex>> GetListAsync(int orderType, List<string> orderNos);
@ -20,15 +27,8 @@ public interface ITrackDetailsRepository
/// <summary> /// <summary>
/// 删除轨迹 /// 删除轨迹
/// </summary> /// </summary>
/// <param name="orderId"></param> /// <param name="orderIds"></param>
/// <param name="trackCodes"></param> /// <param name="trackCodes"></param>
/// <returns></returns> /// <returns></returns>
Task<bool> DeleteTrackAsync(int orderId, List<string> trackCodes); Task<bool> DeleteTrackAsync(int[] orderIds, List<string> trackCodes);
/// <summary>
/// 获取最近一条发生的轨迹
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
Task<TrackDetailsIndex?> GetLatestAsync(int orderId);
} }

View File

@ -35,4 +35,5 @@ public interface ITrackPushConfigRepository : IBasicRepository<TrackPushConfigEn
Task<bool> UpdateContentAsync(Expression<Func<TrackPushContentConfigEntity, bool>> columns, Task<bool> UpdateContentAsync(Expression<Func<TrackPushContentConfigEntity, bool>> columns,
Expression<Func<TrackPushContentConfigEntity, bool>> whereExpression); Expression<Func<TrackPushContentConfigEntity, bool>> whereExpression);
Task<List<QueryTrackPullMappingsInfoVO>> QueryTrackPullMappingsAsync(QueryTrackPullMappingsInputVO input);
} }

View File

@ -7,6 +7,11 @@ public partial class GlobalConst
/// </summary> /// </summary>
public const string TrackUpsertSubscribe = "SJZY.Track.TrackUpsert"; public const string TrackUpsertSubscribe = "SJZY.Track.TrackUpsert";
/// <summary>
/// 轨迹刷新引发的新增/更新 专用
/// </summary>
public const string TrackUpsertForRefreshSubscribe = "SJZY.Track.TrackUpsertForRefresh";
/// <summary> /// <summary>
/// 无法映射的轨迹新增 /// 无法映射的轨迹新增
/// </summary> /// </summary>

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SJZY.Track.Domain.Dtos.TrackPush
{
/// <summary>
/// 查询轨迹推送关系入参
/// </summary>
public class QueryTrackPullMappingsInfoVO
{
/// <summary>
/// 轨迹代码
/// </summary>
public string? Code { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 服务商轨迹代码
/// </summary>
public string? ServiceCode { get; set; }
/// <summary>
/// 服务商轨迹状态
/// </summary>
public string? Status { get; set; }
/// <summary>
/// 服务商轨迹内容
/// </summary>
public string? Content { get; set; }
/// <summary>
/// 服务商轨迹内容英文
/// </summary>
public string? ContentEn { get; set; }
}
/// <summary>
/// 查询轨迹推送关系返参项
/// </summary>
public class QueryTrackPullMappingsInputVO
{
/// <summary>
/// 子系统id
/// </summary>
public int SubsystemsId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomerId { get; set; }
}
}

View File

@ -16,4 +16,9 @@ public class OrderedTrackCodeDto
/// 是否对外 /// 是否对外
/// </summary> /// </summary>
public bool IsExternal { get; set; } public bool IsExternal { get; set; }
/// <summary>
/// 显示原轨迹
/// </summary>
public bool ShowOrigin { get; set; }
} }

View File

@ -0,0 +1,22 @@
using Nest;
using SJZY.Expand.ElasticSearch;
namespace SJZY.Track.Repository;
public static class EsExtensions
{
public static List<T> ToIdList<T>(this ISearchResponse<T> response) where T : IdBaseIndex
{
var dtos = new List<T>();
foreach (var hit in response.Hits)
{
var dto = hit.Source;
dto.Id = hit.Id;
dtos.Add(dto);
}
return dtos;
}
}

View File

@ -20,20 +20,6 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
Context = SqlsugarScopeBasic.GetContextSafely("default"); Context = SqlsugarScopeBasic.GetContextSafely("default");
} }
public async Task<List<OrderTemplateLinkDto>> GetOrderTemplateLinksAsync(int orderType,
params string[] orderNumbers)
{
return await Context.Queryable<OrderEntity>()
.LeftJoin<OrderTemplateEntity>((a, b) => a.Id == b.OrderId)
.Where(a => a.OrderType == orderType && orderNumbers.Contains(a.OrderNo))
.Select((a, b) => new OrderTemplateLinkDto
{
OrderNo = a.OrderNo,
TemplateId = b.TrackTemplateId
})
.ToListAsync();
}
public async Task<List<OrderTemplateLinkDto>> GetOrderTemplateLinksAsync(int orderType, List<string> orderNumbers) public async Task<List<OrderTemplateLinkDto>> GetOrderTemplateLinksAsync(int orderType, List<string> orderNumbers)
{ {
return await Context.Queryable<OrderEntity>() return await Context.Queryable<OrderEntity>()
@ -49,15 +35,17 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
public async Task<List<OrderedTrackCodeDto>> GetOrderedTrackCodesAsync(List<int> templateIds) public async Task<List<OrderedTrackCodeDto>> GetOrderedTrackCodesAsync(List<int> templateIds)
{ {
return await Context.Queryable<TrackTemplateContentEntity>() return await Context.Queryable<TrackTemplateEntity>()
.LeftJoin<TrackContentEntity>((a, b) => a.TrackContentId == b.Id) .LeftJoin<TrackTemplateContentEntity>((a, b) => a.Id == b.TrackTemplateId)
.Where(a => templateIds.Contains(a.TrackTemplateId)) .LeftJoin<TrackContentEntity>((a, b, c) => b.TrackContentId == c.Id)
.OrderBy(a => a.Sort) .Where(a => templateIds.Contains(a.Id))
.Select((a, b) => new OrderedTrackCodeDto .OrderBy((a, b) => b.Sort)
.Select((a, b, c) => new OrderedTrackCodeDto
{ {
TemplateId = a.TrackTemplateId, TemplateId = a.Id,
Code = b.Code, ShowOrigin = a.ShowOrigin,
IsExternal = a.IsExternal Code = c.Code,
IsExternal = b.IsExternal
}) })
.ToListAsync(); .ToListAsync();
} }

View File

@ -67,16 +67,16 @@ AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;");
#region 订单关联 #region 订单关联
public async Task<List<LinkedOrderVO>> GetLinkedOrdersAsync(int orderId) public async Task<List<LinkedOrderVO>> GetLinkedOrdersAsync(int[] orderIds)
{ {
return await Context.Queryable<OrderLinkEntity>() return await Context.Queryable<OrderLinkEntity>()
.LeftJoin<OrderEntity>((a, b) => a.LinkOrderId == b.Id) .LeftJoin<OrderEntity>((a, b) => a.LinkOrderId == b.Id)
.Where(a => a.OrderId == orderId) .Where(a => orderIds.Contains(a.OrderId))
.Select((a, b) => new LinkedOrderVO .Select((a, b) => new LinkedOrderVO
{ {
OrderId = b.Id, OrderId = b.Id,
OrderType = b.OrderType,
OrderNo = b.OrderNo, OrderNo = b.OrderNo,
OrderType = b.OrderType,
SubSystemId = b.SubSystemId SubSystemId = b.SubSystemId
}) })
.ToListAsync(); .ToListAsync();

View File

@ -2,6 +2,7 @@ using Nest;
using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.Logger;
using SJZY.Expand.ElasticSearch.Services; using SJZY.Expand.ElasticSearch.Services;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Consts;
using SJZY.Track.Domain.Dtos.TrackDetails; using SJZY.Track.Domain.Dtos.TrackDetails;
namespace SJZY.Track.Repository.Repositories; namespace SJZY.Track.Repository.Repositories;
@ -13,29 +14,50 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
{ {
} }
public async Task<TrackDetailsIndex?> GetFirstOrDefaultAsync(int orderId, string trackCode) public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode)
{ {
var r = await Context.SearchAsync<TrackDetailsIndex>(s => s var r = await Context.SearchAsync<TrackDetailsIndex>(s => s
.Source() .Source()
.Query(q => .Query(q =>
q.Term(f => f.OrderId, orderId) q.Terms(t => t
.Field(f => f.OrderId)
.Terms(orderIds))
&& q.Term(f => f.TrackCode.Suffix("keyword"), trackCode) && q.Term(f => f.TrackCode.Suffix("keyword"), trackCode)
&& q.Term(f => f.ServiceProviderName.Suffix("keyword"), GlobalConst.EmptyString)
) )
); );
var res = r.Documents.FirstOrDefault(); return r.ToIdList();
if (res != default && r.Hits.FirstOrDefault() != default)
{
res.Id = r.Hits.FirstOrDefault()!.Id;
} }
return res; public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds)
{
var data = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Source(s => s.Includes(fd => fd
.Field(f => f.TrackEnContent)
.Field(f => f.TrackContent)
.Field(f => f.TrackPlace)
.Field(f => f.TrackTime)
.Field(f => f.TrackTimeZone)
.Field(f => f.OrderId)
))
.Query(q =>
q.Terms(t => t
.Field(f => f.OrderId)
.Terms(orderIds))
&& q.Term(f => f.ServiceProviderName.Suffix("keyword"), GlobalConst.EmptyString)
)
.Sort(s => s.Field(f => f.TrackTime, SortOrder.Descending))
.Size(1)
);
return data.Documents.ToList();
} }
public async Task<bool> AnyAsync(int orderId, DateTime trackTime) public async Task<bool> AnyAsync(int orderId, DateTime trackTime)
{ {
var r = await Context.SearchAsync<TrackDetailsIndex>(x => x var r = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Source(s => s.Includes(fd => fd.Field(f => f.Id))) .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode)))
.Query(q => .Query(q =>
q.Term(f => f.OrderId, orderId) q.Term(f => f.OrderId, orderId)
&& q.Term(f => f.TrackTime, trackTime) && q.Term(f => f.TrackTime, trackTime)
@ -45,26 +67,25 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
return r.Hits.Count > 0; return r.Hits.Count > 0;
} }
public async Task UpsertAsync(TrackDetailsIndex index) public async Task<bool> AnyAsync(int orderId, string originTrackData)
{ {
if (index.Id.IsNullOrWhiteSpace()) var r = await Context.SearchAsync<TrackDetailsIndex>(x => x
{ .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode)))
// 按天写入es .Query(q =>
var r = await Context.IndexAsync(index, request => request q.Term(f => f.OrderId, orderId)
.Index(index.IndexName) && q.Term(f => f.OriginTrackData.Suffix("keyword"), originTrackData)
//.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见 )
); );
if (!r.IsValid) return r.Hits.Count > 0;
{
LogHelper.Error($"轨迹新增失败,原因:{r.DebugInformation}。");
} }
}
else
public async Task UpdateAsync(TrackDetailsIndex track)
{ {
var r = await Context.UpdateAsync<TrackDetailsIndex>(index.Id, u => u var r = await Context.UpdateAsync<TrackDetailsIndex>(track.Id, u => u
.Index(index.IndexName) .Index(track.IndexName)
.Doc(index) .Doc(track)
//.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见 //.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见
); );
@ -73,6 +94,18 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
LogHelper.Error($"轨迹更新失败,原因:{r.DebugInformation}。"); LogHelper.Error($"轨迹更新失败,原因:{r.DebugInformation}。");
} }
} }
public async Task AddManyAsync(List<TrackDetailsIndex> tracks)
{
if (!tracks.Any()) return;
// 按天写入es
var r = await Context.IndexManyAsync(tracks, tracks.First().IndexName);
if (!r.IsValid)
{
LogHelper.Error($"{tracks.Count}条轨迹新增失败,原因:{r.DebugInformation}。");
}
} }
public async Task<List<TrackDetailsIndex>> GetListAsync(int orderType, List<string> orderNos) public async Task<List<TrackDetailsIndex>> GetListAsync(int orderType, List<string> orderNos)
@ -85,6 +118,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
.Field(f => f.TrackStatus) .Field(f => f.TrackStatus)
.Field(f => f.TrackCode) .Field(f => f.TrackCode)
.Field(f => f.TrackContent) .Field(f => f.TrackContent)
.Field(f => f.OriginTrackContent)
.Field(f => f.TrackPlace) .Field(f => f.TrackPlace)
.Field(f => f.TrackTime) .Field(f => f.TrackTime)
.Field(f => f.TrackTimeZone) .Field(f => f.TrackTimeZone)
@ -139,32 +173,12 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
return data.Documents.ToList(); return data.Documents.ToList();
} }
public async Task<TrackDetailsIndex?> GetLatestAsync(int orderId) public async Task<bool> DeleteTrackAsync(int[] orderIds, List<string> trackCodes)
{
var data = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Source(s => s.Includes(fd => fd
.Field(f => f.TrackEnContent)
.Field(f => f.TrackContent)
.Field(f => f.TrackPlace)
.Field(f => f.TrackTime)
.Field(f => f.TrackTimeZone)
))
.Query(q =>
q.Term(f => f.OrderId, orderId)
)
.Sort(s => s.Field(f => f.TrackTime, SortOrder.Descending))
.Size(1)
);
return data.Documents.FirstOrDefault();
}
public async Task<bool> DeleteTrackAsync(int orderId, List<string> trackCodes)
{ {
var r = await Context.DeleteByQueryAsync<TrackDetailsIndex>(x => x var r = await Context.DeleteByQueryAsync<TrackDetailsIndex>(x => x
.Query( .Query(
q => q =>
q.Term(t => t.OrderId, orderId) q.Terms(t => t.Field(f => f.OrderId).Terms(orderIds))
&& q.Term(t => t.IsCanDelete, true) && q.Term(t => t.IsCanDelete, true)
&& q.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes))) && q.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes)))
//.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见 //.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见

View File

@ -166,4 +166,29 @@ public class TrackPushConfigRepository : BasicRepository<TrackPushConfigEntity>,
return await Context.Updateable<TrackPushContentConfigEntity>().SetColumns(columns).Where(whereExpression) return await Context.Updateable<TrackPushContentConfigEntity>().SetColumns(columns).Where(whereExpression)
.ExecuteCommandHasChangeAsync(); .ExecuteCommandHasChangeAsync();
} }
/// <summary>
/// 查询轨迹推送关系
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<List<QueryTrackPullMappingsInfoVO>> QueryTrackPullMappingsAsync(QueryTrackPullMappingsInputVO input)
{
var result = await Context.Queryable<TrackPushConfigEntity>().LeftJoin<TrackPushContentConfigEntity>((a, b) => a.Id == b.TrackPushConfigId && !b.IsDeleted)
.LeftJoin<TrackContentEntity>((a, b, c) => b.TrackContentId == c.Id && !c.IsDeleted)
.Where((a, b, c) => !a.IsDeleted)
.Where((a, b, c) => a.SubSystemId == input.SubsystemsId && a.CustomId == input.CustomerId)
.Select((a, b, c) => new QueryTrackPullMappingsInfoVO
{
Code = c.Code,
OrderType = b.OrderNoType,
ServiceCode = b.TrackContentCodeValue,
Status = b.TrackStatusValue,
Content = b.TrackContentValue,
ContentEn = b.TrackEnContentValue
})
.ToListAsync();
return result;
}
} }