Merge pull request 'S06' (#77) from S06 into uat
Reviewed-on: https://git.shijizhongyun.com/Dotnet/SJZY.Track.Api/pulls/77
This commit is contained in:
commit
75dfc93101
@ -1,16 +1,16 @@
|
||||
{
|
||||
"Configuration": {
|
||||
"UseLocalConfiguration": true,
|
||||
"UseLocalConfiguration": false,
|
||||
//是否使用本地配置文件
|
||||
"ConfiguraFileName": "appsettings.Development.json",
|
||||
//指定配置文件名称,开启UseLocalConfiguration时生效
|
||||
"Apollo": {
|
||||
"AppId": "SJZY.Track.Configuration",
|
||||
"Env": "DEV",
|
||||
"Namespace": "dev",
|
||||
"MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080",
|
||||
"Namespace": "test",
|
||||
"MetaServer": "https://apollo.test.shijizhongyun.com",
|
||||
"ConfigServer": [
|
||||
"http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080"
|
||||
"https://apollo.test.shijizhongyun.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@ -10,4 +10,14 @@ public class BatchDeleteTrackInput : OrderNosInfo
|
||||
[Required]
|
||||
[MaxLength(500)]
|
||||
public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么字段比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,比较值
|
||||
/// </summary>
|
||||
public object? CompareValue { get; set; }
|
||||
}
|
||||
|
||||
@ -120,8 +120,23 @@ public class BatchUpsertTrackInput : OrderNosInfo
|
||||
[Range(-12, 12)]
|
||||
public float? DestinationTimeZone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public Dictionary<string,object>? Extra { get; set; }
|
||||
public string? Extra { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否强制推送
|
||||
/// </summary>
|
||||
public bool ForcedPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指定是否推送
|
||||
/// </summary>
|
||||
public bool IsToMq { get; set; }
|
||||
}
|
||||
|
||||
@ -9,8 +9,22 @@ public class DeleteOrderInput : OrderNoInfo
|
||||
public class DeleteTrackInput : OrderNoInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 轨迹标识符集合,必填
|
||||
/// 轨迹标识符集合,为支持esid删除,所以非必填
|
||||
/// </summary>
|
||||
[Required]
|
||||
public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = new();
|
||||
public List<TrackIdentifierDto>? TrackIdentifiers { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹ESId集合,非必填,如果有优先级最高
|
||||
/// </summary>
|
||||
public List<string>? EsIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么字段比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,比较值
|
||||
/// </summary>
|
||||
public object? CompareValue { get; set; }
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||
|
||||
/// <summary>
|
||||
/// 支持模板,传入时区补正,按轨迹发生时间升序降序
|
||||
/// </summary>
|
||||
public class GetTrackInput : OrderNosInfo
|
||||
{
|
||||
private float? _timeZone;
|
||||
@ -8,11 +11,7 @@ public class GetTrackInput : OrderNosInfo
|
||||
/// 时区 +8 +8.25 -8.5 -9
|
||||
/// 不传默认+8
|
||||
/// </summary>
|
||||
public float? TimeZone
|
||||
{
|
||||
get => _timeZone ?? 8;
|
||||
set => _timeZone = value;
|
||||
}
|
||||
public float? TimeZone { get => _timeZone ?? 8; set => _timeZone = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序方式,默认按轨迹发生时间降序
|
||||
@ -20,15 +19,36 @@ public class GetTrackInput : OrderNosInfo
|
||||
public SortMethod? SortMethod { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 不支持模板,无时区补正,按轨迹发生时间升序降序
|
||||
/// </summary>
|
||||
public class GetTrackInputV2 : OrderNosInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 排序方式,默认按轨迹发生时间降序
|
||||
/// </summary>
|
||||
public SortMethod? SortMethod { get; set; }
|
||||
}
|
||||
|
||||
public enum SortMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// 按轨迹发生时间排序
|
||||
/// </summary>
|
||||
ByTrackTime,
|
||||
ByTrackTime = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 按轨迹发生时间降序
|
||||
/// </summary>
|
||||
ByTrackTimeDesc,
|
||||
ByTrackTimeDesc = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 模板排序+轨迹发生时间
|
||||
/// </summary>
|
||||
ByTemplateAndTrackTime = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 模板排序+轨迹发生时间
|
||||
/// </summary>
|
||||
ByTemplateAndTrackTimeDesc = 3
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ public class GetTrackOutput
|
||||
|
||||
public class TrackDetail
|
||||
{
|
||||
public string EsId { get; set; } = null!;
|
||||
public string Code { get; set; } = null!;
|
||||
public string Status { get; set; } = null!;
|
||||
public string? Content { get; set; }
|
||||
@ -91,7 +92,6 @@ public class TrackDetail
|
||||
/// </summary>
|
||||
public string? TrackPlacePostcode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 预计到达时间
|
||||
/// </summary>
|
||||
@ -105,5 +105,5 @@ public class TrackDetail
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Extra { get; set; }
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
|
||||
@ -9,4 +9,14 @@ public class PushTrackInput : OrderNosInfo
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string TrackCode { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么字段比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,比较值
|
||||
/// </summary>
|
||||
public object? CompareValue { get; set; }
|
||||
}
|
||||
|
||||
@ -44,4 +44,9 @@ public class TemplateContentDto
|
||||
/// 轨迹节点
|
||||
/// </summary>
|
||||
public string Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序键
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ public class UpdateOrderInput : OrderNoInfo
|
||||
/// <summary>
|
||||
/// 模板code
|
||||
/// </summary>
|
||||
public List<string> TemplateCodes { get; set; }
|
||||
public List<string>? TemplateCodes { get; set; }
|
||||
}
|
||||
|
||||
public class PullConfigInfo
|
||||
|
||||
@ -9,6 +9,11 @@ public class UpsertTrackInput : OrderNoInfo
|
||||
/// </summary>
|
||||
public bool IsAdd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹唯一标识(可选)
|
||||
/// </summary>
|
||||
public string? EsId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹内容代码
|
||||
/// </summary>
|
||||
@ -27,7 +32,7 @@ public class UpsertTrackInput : OrderNoInfo
|
||||
/// 轨迹发生时间
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime? TrackTime { get; set; }
|
||||
public DateTime TrackTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更改后的轨迹发生时间,无需更改保持为空
|
||||
@ -124,8 +129,23 @@ public class UpsertTrackInput : OrderNoInfo
|
||||
/// </summary>
|
||||
public int OptionUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Extra { get; set; }
|
||||
public string? Extra { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否强制推送
|
||||
/// </summary>
|
||||
public bool ForcedPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指定是否推送
|
||||
/// </summary>
|
||||
public bool IsToMq { get; set; }
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ public class GetAvailableContentInput
|
||||
public string? OrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作类型 1=创建 2=修改 3=删除
|
||||
/// 操作类型 1=创建 2=修改 3=删除 4=推送
|
||||
/// </summary>
|
||||
public TrackOptionType TrackOptionType { get; set; }
|
||||
}
|
||||
@ -22,5 +22,6 @@ public enum TrackOptionType
|
||||
{
|
||||
创建 = 1,
|
||||
修改 = 2,
|
||||
删除 = 3
|
||||
删除 = 3,
|
||||
推送 = 4,
|
||||
}
|
||||
|
||||
@ -44,10 +44,15 @@ public class EditTrackPushConfigInput
|
||||
/// </summary>
|
||||
public bool? IsAllPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否全量推送
|
||||
/// </summary>
|
||||
public bool? IsAllPushWithLatest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间格式枚举
|
||||
/// </summary>
|
||||
public int DateTimeFormatType { get; set; }
|
||||
public int? DateTimeFormatType { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 日期时间格式模板
|
||||
|
||||
@ -17,6 +17,11 @@ public class TrackPushContentConfigDto
|
||||
/// </summary>
|
||||
public bool IsAllPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否全量推送(最新轨迹)
|
||||
/// </summary>
|
||||
public bool IsAllPushWithLatest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持删除
|
||||
/// </summary>
|
||||
@ -70,6 +75,7 @@ public class TrackPushContentConfigDto
|
||||
/// <summary>
|
||||
/// 扩展字段参数值
|
||||
/// </summary>
|
||||
[Obsolete("废弃属性,调整为从轨迹明细扩展中获取扩展值填入")]
|
||||
public string? ExpandFieldsValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -4,7 +4,8 @@ public class TrackPushInput
|
||||
{
|
||||
public string OrderNo { get; set; } = null!;
|
||||
|
||||
public List<TrackItem> Data { get; set; } = new();
|
||||
//原TrackItem,为了扩展字段入参变更为字典
|
||||
public List<Dictionary<string,object?>> Data { get; set; } = new();
|
||||
|
||||
public string Log { get; set; }
|
||||
}
|
||||
@ -13,19 +14,8 @@ public class TrackUpdateInput
|
||||
{
|
||||
public string OrderNo { get; set; } = null!;
|
||||
|
||||
public List<TrackItem> Data { get; set; } = new();
|
||||
//原TrackItem,为了扩展字段入参变更为字典
|
||||
public List<Dictionary<string,object?>> Data { get; set; } = new();
|
||||
|
||||
public string Log { get; set; }
|
||||
}
|
||||
|
||||
public class TrackItem
|
||||
{
|
||||
public string Location { get; set; } = null!;
|
||||
public string 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; }
|
||||
}
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
namespace SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||
|
||||
public class TrackPushRecordDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 子系统代码
|
||||
/// </summary>
|
||||
public string SubSystemCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为手动推送
|
||||
/// </summary>
|
||||
public bool IsManualPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送时间
|
||||
/// </summary>
|
||||
public DateTime PushTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string? OperationMan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单号
|
||||
/// </summary>
|
||||
public string OrderNo { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 接口通请求Id
|
||||
/// 在请求接口通前被拦截,就不会有请求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 bool IsSuccess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送内容(json)
|
||||
/// </summary>
|
||||
public string PushContent { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹的额外新
|
||||
/// </summary>
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
@ -128,4 +128,9 @@ public class TrackChangeEto
|
||||
/// 预计到达时间
|
||||
/// </summary>
|
||||
public DateTime? EstimatedDeliveryDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
|
||||
@ -12,17 +12,27 @@ public class TrackDeleteEvent
|
||||
/// <summary>
|
||||
/// es中的id
|
||||
/// </summary>
|
||||
public string[] EsIds { get; set; }
|
||||
public string[]? EsIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单ids
|
||||
/// </summary>
|
||||
public int[] OrderIds { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么字段比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,比较值
|
||||
/// </summary>
|
||||
public object? CompareValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹标识符
|
||||
/// </summary>
|
||||
public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = null!;
|
||||
public List<TrackIdentifierDto>? TrackIdentifiers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
namespace SJZY.Track.Application.Contract.Events;
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹推送广播模型
|
||||
/// </summary>
|
||||
public class TrackPushCompletedEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否为手动推送
|
||||
/// </summary>
|
||||
public bool IsManualPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送时间
|
||||
/// </summary>
|
||||
public DateTime PushTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string? OperationMan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单号
|
||||
/// </summary>
|
||||
public string OrderNo { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 接口通请求Id
|
||||
/// 在请求接口通前被拦截,就不会有请求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 bool IsSuccess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送内容(json)
|
||||
/// </summary>
|
||||
public string PushContent { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹的额外新
|
||||
/// </summary>
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
@ -41,6 +41,16 @@ public class TrackPushEvent
|
||||
/// 系统推送信息
|
||||
/// </summary>
|
||||
public SystemPushStruct SystemPushInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否强制推送
|
||||
/// </summary>
|
||||
public bool ForcedPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否发送到mq
|
||||
/// </summary>
|
||||
public bool IsToMq { get; set; }
|
||||
}
|
||||
|
||||
public struct SystemPushStruct
|
||||
@ -69,4 +79,14 @@ public struct SystemPushStruct
|
||||
/// 轨迹发生时区
|
||||
/// </summary>
|
||||
public float TrackTimeZone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
|
||||
@ -19,6 +19,11 @@ public class TrackUpsertEvent
|
||||
/// </summary>
|
||||
public OrderIdentifier[] OrderIdentifiers { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹唯一标识(用于单个订单更新单条轨迹,如果有的话优先级最高)
|
||||
/// </summary>
|
||||
public string? EsId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人(null则默认系统)
|
||||
/// </summary>
|
||||
@ -141,10 +146,25 @@ public class TrackUpsertEvent
|
||||
/// </summary>
|
||||
public float? DestinationTimeZone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复的情况下,用什么比较
|
||||
/// </summary>
|
||||
public string? CompareFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Extra { get; set; }
|
||||
public string? Extra { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否强制推送
|
||||
/// </summary>
|
||||
public bool ForcedPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指定是否推送
|
||||
/// </summary>
|
||||
public bool IsToMq { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<Version>7.0.3</Version>
|
||||
<Version>7.0.14</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||
using SJZY.Track.Application.Contract.Events;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
|
||||
namespace SJZY.Track.Application.Contract.Services;
|
||||
|
||||
public interface IBroadcastingService : ITransientDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 轨迹变更广播(新增/修改)
|
||||
/// </summary>
|
||||
/// <param name="eto"></param>
|
||||
/// <param name="subSystemCode"></param>
|
||||
/// <param name="trackStatusCode"></param>
|
||||
void TrackChangePublicTopic(TrackUpsertEvent eto, string subSystemCode, string trackStatusCode);
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹变更广播(删除)
|
||||
/// </summary>
|
||||
/// <param name="eto"></param>
|
||||
/// <param name="subSystemCode"></param>
|
||||
/// <param name="trackStatusCode"></param>
|
||||
void TrackChangePublicTopic(TrackDeleteEvent eto, OrderIdentifier[] orderIdentifiers, string trackCode, string trackStatusCode, string subSystemCode);
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹变更广播(删除)
|
||||
/// </summary>
|
||||
/// <param name="eto"></param>
|
||||
/// <param name="subSystemCode"></param>
|
||||
/// <param name="trackStatusCode"></param>
|
||||
void TrackChangePublicTopic(TrackChangeEto eto, string subSystemCode);
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹推送完成广播(推送完成回调)
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
void TrackPushCompletedPublicTopic(TrackPushRecordDto log);
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹推送失败广播(推送前置被拦截,或调用接口通失败)
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
void TrackPushFailedPubilcTopic(TrackPushRecordDto log);
|
||||
}
|
||||
@ -12,7 +12,7 @@ public interface ITrackPushService : IRemoteService
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public Task<string> PushTrackAsync(PushTrackInput input);
|
||||
public Task<UnifyResultDto> PushTrackAsync(PushTrackInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 获取轨迹推送内容
|
||||
@ -20,12 +20,12 @@ public interface ITrackPushService : IRemoteService
|
||||
/// <returns></returns>
|
||||
/// <param name="subSystemId">子系统id</param>
|
||||
/// <param name="customerId">客户id</param>
|
||||
public Task<List<TrackPushContentDto>> GetTrackPushContentListAsync(int subSystemId, int customerId);
|
||||
public Task<UnifyResultDto<List<TrackPushContentDto>>> GetTrackPushContentListAsync(int subSystemId, int customerId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取轨迹推送记录
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public Task<List<TrackPushRecordOutput>> GetTrackPushRecordsAsync(OrderNoInfo input);
|
||||
public Task<UnifyResultDto<List<TrackPushRecordOutput>>> GetTrackPushRecordsAsync(OrderNoInfo input);
|
||||
}
|
||||
|
||||
@ -12,6 +12,13 @@ public interface ITrackService : IRemoteService
|
||||
/// <returns></returns>
|
||||
Task<UnifyResultDto> UpsertTrackAsync(UpsertTrackInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 批量新增/更新订单轨迹接口
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<UnifyResultDto> BatchUpsertTrackAsync(BatchUpsertTrackInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 删除轨迹
|
||||
/// </summary>
|
||||
@ -28,8 +35,17 @@ public interface ITrackService : IRemoteService
|
||||
|
||||
/// <summary>
|
||||
/// 根据订单号获取轨迹
|
||||
/// 支持模板,传入时区补正,按轨迹发生时间升序降序
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<UnifyResultDto<List<GetTrackOutput>>> QueryAsync(GetTrackInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 根据订单号获取轨迹
|
||||
/// 不支持模板,无时区补正,可按轨迹发生时间升序降序
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<UnifyResultDto<List<GetTrackOutput>>> QueryV2Async(GetTrackInputV2 input);
|
||||
}
|
||||
|
||||
@ -26,8 +26,6 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
|
||||
return;
|
||||
}
|
||||
|
||||
//指示是否需要更新【预计签收时间】【签收地时区】
|
||||
var isNeedUpdate = false;
|
||||
var updateOrders = new List<OrderEntity>();
|
||||
foreach (var order in orders)
|
||||
{
|
||||
@ -62,37 +60,23 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
|
||||
{
|
||||
order.EstimatedDeliveryDate = @event.EstimatedDeliveryDate.Value;
|
||||
order.DestinationTimeZone = @event.DestinationTimeZone.Value;
|
||||
isNeedUpdate = true;
|
||||
}
|
||||
|
||||
updateOrders.Add(order);
|
||||
}
|
||||
|
||||
await _orderRepository.UpdateRangeAsync(updateOrders,
|
||||
isNeedUpdate
|
||||
? x => new
|
||||
{
|
||||
x.IsCompleted,
|
||||
x.LatestTrackContent,
|
||||
x.LatestTrackEnContent,
|
||||
x.LatestTrackPlace,
|
||||
x.LatestTrackTime,
|
||||
x.LatestTrackTimeZone,
|
||||
x.DeficiencyTag,
|
||||
//当标识指示需要更新时添加更新列
|
||||
x.EstimatedDeliveryDate,
|
||||
x.DestinationTimeZone
|
||||
}
|
||||
: x => new
|
||||
{
|
||||
x.IsCompleted,
|
||||
x.LatestTrackContent,
|
||||
x.LatestTrackEnContent,
|
||||
x.LatestTrackPlace,
|
||||
x.LatestTrackTime,
|
||||
x.LatestTrackTimeZone,
|
||||
x.DeficiencyTag,
|
||||
}
|
||||
await _orderRepository.UpdateRangeAsync(updateOrders, x => new
|
||||
{
|
||||
x.IsCompleted,
|
||||
x.LatestTrackContent,
|
||||
x.LatestTrackEnContent,
|
||||
x.LatestTrackPlace,
|
||||
x.LatestTrackTime,
|
||||
x.LatestTrackTimeZone,
|
||||
x.DeficiencyTag,
|
||||
x.EstimatedDeliveryDate,
|
||||
x.DestinationTimeZone
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -109,6 +93,8 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
|
||||
LatestTrackPlace = order.LatestTrackPlace,
|
||||
LatestTrackTime = order.LatestTrackTime,
|
||||
LatestTrackTimeZone = order.LatestTrackTimeZone,
|
||||
DestinationTimeZone = order.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = order.EstimatedDeliveryDate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
using System.Text;
|
||||
using BSI.Stack.Rabbit;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json;
|
||||
using DotNetCore.CAP;
|
||||
using SJZY.Expand.ABP.Core.Logger;
|
||||
using SJZY.Expand.ABP.Core.PublicMethords;
|
||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||
using SJZY.Track.Application.Contract.Events;
|
||||
using SJZY.Track.Application.Contract.Services;
|
||||
using SJZY.Track.Application.Helpers;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.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;
|
||||
@ -18,30 +18,24 @@ namespace SJZY.Track.Application.CAP.EventHandlers;
|
||||
public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
{
|
||||
private readonly ICapPublisher _capPublisher;
|
||||
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly ITrackStatusRepository _trackStatusRepository;
|
||||
private readonly ITrackContentRepository _trackContentRepository;
|
||||
private readonly IProvideQueries _provideQueries;
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
private readonly RabbitClientBus _rabbitClientBus;
|
||||
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
||||
private readonly IBroadcastingService _broadcastingService;
|
||||
|
||||
public TrackDeleteEventHandler(IProvideQueries provideQueries,
|
||||
IOrderRepository orderRepository, ICapPublisher capPublisher,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||
RabbitClientBus rabbitClientBus,
|
||||
ITrackStatusRepository trackStatusRepository,
|
||||
ITrackContentRepository trackContentRepository,
|
||||
IOrderOperationRecordEsRepository orderOperationRecordEsRepository)
|
||||
IOrderOperationRecordEsRepository orderOperationRecordEsRepository,
|
||||
IBroadcastingService broadcastingService)
|
||||
{
|
||||
_provideQueries = provideQueries;
|
||||
_orderRepository = orderRepository;
|
||||
_capPublisher = capPublisher;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
_rabbitClientBus = rabbitClientBus;
|
||||
_trackStatusRepository = trackStatusRepository;
|
||||
_trackContentRepository = trackContentRepository;
|
||||
_orderOperationRecordEsRepository = orderOperationRecordEsRepository;
|
||||
_broadcastingService = broadcastingService;
|
||||
}
|
||||
|
||||
[CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)]
|
||||
@ -51,8 +45,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
|
||||
var trackList = await DeleteTrackAsync(@event);
|
||||
|
||||
//发布事件
|
||||
await PublicTrackTopicAsync(@event, trackList);
|
||||
//当轨迹删除,根据轨迹标记/状态上IsToMq选择进行广播
|
||||
if (trackList.Count != 0)
|
||||
_ = PublicTrackTopicAsync(@event, trackList);
|
||||
|
||||
// 根据订单关联关系异步向下刷(异步)
|
||||
await DownByOrderLink(@event);
|
||||
@ -126,51 +121,6 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task PublicTrackTopicAsync(TrackDeleteEvent eto, List<TrackDetailsIndex> trackList)
|
||||
{
|
||||
if (trackList == null)
|
||||
return;
|
||||
|
||||
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<List<TrackDetailsIndex>> DeleteTrackAsync(TrackDeleteEvent @event)
|
||||
{
|
||||
List<int> orderIds;
|
||||
@ -208,10 +158,40 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
//根据订单查询出所有的轨迹,查所有是因为主单上需要进行回退更新
|
||||
tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds);
|
||||
|
||||
//构建标识符集合
|
||||
var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToList();
|
||||
//根据标识符选出要删除的轨迹明细
|
||||
deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList();
|
||||
//比较字段为空则使用时间来作为额外的标识key
|
||||
if (string.IsNullOrWhiteSpace(@event.CompareFields))
|
||||
{
|
||||
//构建标识符集合
|
||||
var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToHashSet();
|
||||
//根据标识符选出要删除的轨迹明细
|
||||
deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList();
|
||||
}
|
||||
//否则则使用比较字段,使用扩展字段中的内容进行比较
|
||||
else
|
||||
{
|
||||
var codes = @event.TrackIdentifiers.Select(x => x.TrackCode).ToImmutableHashSet();
|
||||
deleteTracks = tracks
|
||||
.Where(x =>
|
||||
{
|
||||
if (!codes.Contains(x.TrackCode))
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(x.Extra))
|
||||
{
|
||||
throw new BusinessException(message: $"当前轨迹不存在扩展信息,无法利用扩展字段:{@event.CompareFields}");
|
||||
}
|
||||
|
||||
var extraDict = TextJsonHelper.DeserializeToDictionary(x.Extra);
|
||||
if (extraDict == null || !extraDict.TryGetValue(@event.CompareFields, out var compareValue))
|
||||
{
|
||||
throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{@event.CompareFields}");
|
||||
}
|
||||
|
||||
return TextJsonHelper.EqJsonElement(compareValue, @event.CompareValue);
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
if (deleteTracks.Count == 0) return deleteTracks;
|
||||
|
||||
@ -225,7 +205,8 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
}
|
||||
|
||||
//排除掉已经删除的轨迹
|
||||
tracks = tracks.Except(deleteTracks).ToList();
|
||||
var deleteTrackIds = deleteTracks.Select(m => m.Id).ToList();
|
||||
tracks = tracks.Where(x => !deleteTrackIds.Contains(x.Id)).ToList();
|
||||
|
||||
var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id),
|
||||
x => new OrderEntity
|
||||
@ -267,21 +248,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
order.EstimatedDeliveryDate = track.EstimatedDeliveryDate;
|
||||
order.DestinationTimeZone = track.DestinationTimeZone;
|
||||
}
|
||||
|
||||
|
||||
// 写入操作日志
|
||||
_ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex
|
||||
{
|
||||
OrderId = order.Id,
|
||||
OrderNo = order.OrderNo,
|
||||
OptionType = OrderOperationType.删除轨迹.ToString(),
|
||||
Content = deleteTracks?.Where(m => m.OrderId == order.Id).ToList().ToJson(),
|
||||
CreateUserId = @event.OperationManId,
|
||||
CreateUserName = @event.OperationMan ?? "",
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
|
||||
//更新订单上冗余轨迹明细的字段
|
||||
await _orderRepository.UpdateRangeAsync(orders,
|
||||
x => new
|
||||
{
|
||||
@ -294,6 +263,104 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||
x.DestinationTimeZone
|
||||
});
|
||||
|
||||
//批量写入订单操作日志
|
||||
_ = _orderOperationRecordEsRepository.AddManyAsync(orders.Select(order => new OrderOperationRecordIndex
|
||||
{
|
||||
OrderId = order.Id,
|
||||
OrderNo = order.OrderNo,
|
||||
OptionType = OrderOperationType.删除轨迹.ToString(),
|
||||
Content = deleteTracks.Where(m => m.OrderId == order.Id).ToList().ToJson(),
|
||||
CreateUserId = @event.OperationManId,
|
||||
CreateUserName = @event.OperationMan ?? "",
|
||||
CreateTime = DateTime.Now
|
||||
}).ToList());
|
||||
|
||||
return deleteTracks;
|
||||
}
|
||||
|
||||
private async Task PublicTrackTopicAsync(TrackDeleteEvent @event, List<TrackDetailsIndex> trackList)
|
||||
{
|
||||
var systemIds = trackList.Select(x => x.SubSystemId).Distinct().ToArray();
|
||||
var trackCodes = trackList.Select(x => x.TrackCode).Distinct().ToArray();
|
||||
|
||||
//从轨迹内容中查询出标记是否需要mq广播
|
||||
var contentList = await _provideQueries.GetTrackContentsAsync(systemIds, trackCodes);
|
||||
var toMqDict = contentList
|
||||
.ToDictionary(x => x.SubSystemId + x.TrackContentCode, y => y.IsToMq);
|
||||
|
||||
//选出需要广播的轨迹,并按code和订单号分组
|
||||
var trackGroup = trackList
|
||||
.Where(x => toMqDict[x.SubSystemId + x.TrackCode])
|
||||
.GroupBy(m => new
|
||||
{
|
||||
m.TrackCode,
|
||||
m.OrderNo
|
||||
})
|
||||
.ToList();
|
||||
if (trackGroup.Count == 0) return;
|
||||
|
||||
//增加延时确保写盘成功
|
||||
await Task.Delay(1000);
|
||||
foreach (var dataItem in trackGroup)
|
||||
{
|
||||
var item = dataItem.First();
|
||||
var content = contentList.First(m => m.TrackContentCode == item.TrackCode);
|
||||
|
||||
// _broadcastingService.TrackChangePublicTopic(track,
|
||||
// dataItem.Select(m => new OrderIdentifier
|
||||
// {
|
||||
// OrderId = m.OrderId,
|
||||
// OrderNo = m.OrderNo,
|
||||
// OrderType = m.OrderType
|
||||
// }).ToArray(),
|
||||
// item.TrackCode,
|
||||
// item.TrackStatusCode,
|
||||
// content.SubSystemCode
|
||||
// );
|
||||
|
||||
//将每个订单的每个轨迹的删除变更发布
|
||||
foreach (var track in dataItem)
|
||||
{
|
||||
_broadcastingService.TrackChangePublicTopic(new TrackChangeEto
|
||||
{
|
||||
EstimatedDeliveryDate = track.EstimatedDeliveryDate,
|
||||
TrackPlacePostcode = track.TrackPlacePostcode,
|
||||
TrackPlaceNation = track.TrackPlaceNation,
|
||||
TrackPlaceNationId = track.TrackPlaceNationId,
|
||||
TrackPlaceProvince = track.TrackPlaceProvince,
|
||||
TrackPlaceProvinceId = track.TrackPlaceProvinceId,
|
||||
TrackPlaceCity = track.TrackPlaceCity,
|
||||
TrackPlaceCityId = track.TrackPlaceCityId,
|
||||
Files = track.Files?.Select(x => new FileItemDto()
|
||||
{
|
||||
FileName = x.FileName,
|
||||
OssKey = x.OssKey
|
||||
}).ToList(),
|
||||
Remarks = track.Remarks,
|
||||
Source = track.Source,
|
||||
IsVisibility = track.IsVisibility,
|
||||
TrackTimeZone = track.TrackTimeZone,
|
||||
TrackTime = track.TrackTime,
|
||||
TrackPlace = track.TrackPlace,
|
||||
TrackStatusCode = track.TrackStatusCode,
|
||||
EnStatus = track.TrackEnContent,
|
||||
Content = track.TrackContent,
|
||||
TrackCode = track.TrackCode,
|
||||
OperationMan = @event.OperationMan,
|
||||
OrderNo = track.OrderNo,
|
||||
OrderIdentifiers = new[]
|
||||
{
|
||||
new OrderIdentifier()
|
||||
{
|
||||
OrderId = track.OrderId,
|
||||
OrderNo = track.OrderNo,
|
||||
OrderType = track.OrderType
|
||||
}
|
||||
},
|
||||
SubSystemId = @event.SubSystemId,
|
||||
Extra = track.Extra
|
||||
}, content.SubSystemCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json;
|
||||
using DotNetCore.CAP;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
@ -23,23 +25,28 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
private readonly IHttpClientProxy<IInterfaceForwardServiceV2> _httpClientProxy;
|
||||
private readonly IOptionsMonitor<InterfaceRelayParamsConfigOptions> _options;
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
private readonly ITrackPushCacheService _trackPushCacheService;
|
||||
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
private readonly IBroadcastingService _broadcastingService;
|
||||
private List<OrderEntity> _orders = null!;
|
||||
private List<TrackPushContentConfigDto> _pushConfigs = null!;
|
||||
|
||||
public TrackPushEventHandler(IHttpClientProxy<IInterfaceForwardServiceV2> httpClientProxy,
|
||||
IOrderRepository orderRepository, ITrackPushCacheService trackPushCacheService,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository, ITrackPushRecordEsRepository trackPushRecordEsRepository,
|
||||
IOptionsMonitor<InterfaceRelayParamsConfigOptions> options)
|
||||
IOrderRepository orderRepository,
|
||||
ITrackPushCacheService trackPushCacheService,
|
||||
ITrackPushRecordEsRepository trackPushRecordEsRepository,
|
||||
IOptionsMonitor<InterfaceRelayParamsConfigOptions> options,
|
||||
IBroadcastingService broadcastingService,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository)
|
||||
{
|
||||
_httpClientProxy = httpClientProxy;
|
||||
_orderRepository = orderRepository;
|
||||
_trackPushCacheService = trackPushCacheService;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
_trackPushRecordEsRepository = trackPushRecordEsRepository;
|
||||
_options = options;
|
||||
_broadcastingService = broadcastingService;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
}
|
||||
|
||||
[CapSubscribe(GlobalConst.TrackPushSubscribe, Group = GlobalConst.TrackPushSubscribe)]
|
||||
@ -67,6 +74,13 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
if (orders.Count == 0) return;
|
||||
_orders = orders;
|
||||
|
||||
if (@event.ForcedPush)
|
||||
{
|
||||
//当为强制推送,会走手动推送逻辑
|
||||
await DoPushAsync(@event);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (@event.OptionType)
|
||||
{
|
||||
case OptionType.无:
|
||||
@ -86,76 +100,22 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
|
||||
private async Task DoPushAsync(TrackPushEvent @event)
|
||||
{
|
||||
var items = new List<object>();
|
||||
TrackPushContentConfigDto? config;
|
||||
|
||||
var items = new List<TrackPushInput>();
|
||||
if (@event.OperationMan == null)
|
||||
{
|
||||
foreach (var order in _orders)
|
||||
if (@event.OptionType == OptionType.新增)
|
||||
{
|
||||
if (order.QuestionType == (int) TrackProblemType.Error) continue; // 系统不推异常单,只能人工操作
|
||||
// 推送新增,需要根据上一次的推送 推断 本次推送 是否可行
|
||||
config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event.TrackCode);
|
||||
if (config == null) continue;
|
||||
if (!config.IsAutoPush) continue;
|
||||
if (config.OrderType != order.OrderType) continue;
|
||||
|
||||
var log = new TrackPushRecordIndex
|
||||
{
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
OrderId = order.Id,
|
||||
OrderNo = order.OrderNo,
|
||||
TrackStatus = @event.SystemPushInfo.TrackStatus,
|
||||
TrackCode = @event.TrackCode,
|
||||
TrackContent = @event.SystemPushInfo.TrackContent,
|
||||
TrackPlace = @event.SystemPushInfo.TrackPlace,
|
||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||
CreateUser = GlobalConst.SystemUser,
|
||||
};
|
||||
var item = await BuiltPushItem(config, log);
|
||||
item.Log = JsonConvert.SerializeObject(log);
|
||||
items.Add(item);
|
||||
await BuiltSystemPushItemsAsync(@event, items);
|
||||
}
|
||||
else if (@event.OptionType == OptionType.修改)
|
||||
{
|
||||
await BuiltManualPushItemsAsync(@event, items);
|
||||
}
|
||||
}
|
||||
else //手工推送
|
||||
else
|
||||
{
|
||||
config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode);
|
||||
if (config == null) return;
|
||||
|
||||
var tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds, @event.TrackCode);
|
||||
tracks = tracks.DistinctBy(x => x.OrderId).ToList(); // 防止重复推送
|
||||
if (tracks.Count == 0) return; // 一个能推的轨迹都不存在
|
||||
|
||||
// tips:人工推送只要能推就推了,不会校验已推和顺序问题,因为可能是更新
|
||||
foreach (var track in tracks)
|
||||
{
|
||||
var order = _orders.First(x => x.Id == track.OrderId);
|
||||
if (config is { IsAllPush: true })
|
||||
{
|
||||
// 推断 本次推送 是否可行
|
||||
config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event.TrackCode);
|
||||
}
|
||||
|
||||
if (config == null) continue;
|
||||
|
||||
var log = new TrackPushRecordIndex
|
||||
{
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
OrderId = track.OrderId,
|
||||
OrderNo = order.OrderNo,
|
||||
TrackStatus = track.TrackStatus,
|
||||
TrackCode = @event.TrackCode,
|
||||
TrackContent = track.TrackContent,
|
||||
TrackPlace = track.TrackPlace,
|
||||
TrackTime = track.TrackTime,
|
||||
TrackTimeZone = track.TrackTimeZone,
|
||||
CreateUser = @event.OperationMan,
|
||||
};
|
||||
var item = await BuiltPushItem(config, log);
|
||||
item.Log = JsonConvert.SerializeObject(log);
|
||||
items.Add(item);
|
||||
}
|
||||
// 手工推送,不会校验已推和顺序问题,因为可能是更新
|
||||
await BuiltManualPushItemsAsync(@event, items);
|
||||
}
|
||||
|
||||
if (items.Count == 0) return;
|
||||
@ -164,26 +124,119 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode)))
|
||||
{
|
||||
var asciiString = Base64Helper.SerializeObject(OptionType.新增.ToString());
|
||||
var serviceProviderCode = _pushConfigs.First().ServiceProviderCode;
|
||||
var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
|
||||
_options.CurrentValue.PushTrackInterfaceCode,
|
||||
_pushConfigs.First().ServiceProviderCode, items, GlobalConst.TrackPushCompletedSubscribe,
|
||||
serviceProviderCode, items.Cast<object>().ToList(), GlobalConst.TrackPushCompletedSubscribe,
|
||||
attach: asciiString);
|
||||
|
||||
if (r.Code != GlobalConst.SuccessCode)
|
||||
{
|
||||
throw new BusinessException(message: $"requestId: {r.RequestId}; {r.Msg}");
|
||||
TrackPushFailedPublicTopic($"轨迹中台调用接口通失败,RequestId: {r.RequestId}; Msg: {r.Msg}", @event, r.RequestId,
|
||||
items.Cast<dynamic>().ToList());
|
||||
throw new BusinessException(
|
||||
message: $"requestId: {r.RequestId}; serviceProviderCode:{serviceProviderCode} Msg: {r.Msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DoUpdateAsync(TrackPushEvent @event)
|
||||
private async Task BuiltManualPushItemsAsync(TrackPushEvent @event, List<TrackPushInput> items)
|
||||
{
|
||||
// tips: 手工强制推送直接使用配置
|
||||
var config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode);
|
||||
if (config == null || !config.IsCanUpdate) return;
|
||||
|
||||
var items = new List<object>();
|
||||
foreach (var order in _orders)
|
||||
{
|
||||
if (config is { IsAllPush: true })
|
||||
{
|
||||
// 非强制推送需要 推断 本次推送 是否可行
|
||||
if (!@event.ForcedPush)
|
||||
{
|
||||
config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event);
|
||||
}
|
||||
}
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
TrackPushFailedPublicTopic("推送顺序异常,找不到有效推送配置", @event, order);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//配置的类型如何和订单类型不一致则不允许推送
|
||||
if (config.OrderType != order.OrderType)
|
||||
{
|
||||
TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event,
|
||||
order);
|
||||
continue;
|
||||
}
|
||||
|
||||
var log = new TrackPushRecordIndex
|
||||
{
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
OrderId = order.Id,
|
||||
OrderNo = order.OrderNo,
|
||||
TrackStatus = @event.SystemPushInfo.TrackStatus,
|
||||
TrackCode = @event.TrackCode,
|
||||
TrackContent = @event.SystemPushInfo.TrackContent,
|
||||
TrackPlace = @event.SystemPushInfo.TrackPlace,
|
||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||
CreateUser = @event.OperationMan,
|
||||
SubSystemCode = @event.SubSystemCode,
|
||||
IsToMq = @event.IsToMq,
|
||||
Extra = @event.SystemPushInfo.Extra
|
||||
};
|
||||
var item = await BuiltPushItem(config, log, @event.SystemPushInfo.CompareFields);
|
||||
item.Log = JsonConvert.SerializeObject(log);
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task BuiltSystemPushItemsAsync(TrackPushEvent @event, List<TrackPushInput> items)
|
||||
{
|
||||
var config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode);
|
||||
foreach (var order in _orders)
|
||||
{
|
||||
if (config == null)
|
||||
{
|
||||
TrackPushFailedPublicTopic($"没有在推送映射配置中找到关于轨迹代码[{@event.TrackCode}]的配置", @event, order);
|
||||
return;
|
||||
}
|
||||
|
||||
// 系统不推异常单,只能人工操作
|
||||
if (order.QuestionType == (int) TrackProblemType.Error)
|
||||
{
|
||||
TrackPushFailedPublicTopic("系统不推异常单,只能人工操作", @event, order);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 推送新增,需要根据上一次的推送 推断 本次推送 是否可行,为了约束顺序
|
||||
// 如果当前推送code与订单上的最后的code不一致,则考虑推送映射顺序
|
||||
if (!string.Equals(order.LatestPushTrackCode, @event.TrackCode))
|
||||
{
|
||||
config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event);
|
||||
if (config == null)
|
||||
{
|
||||
TrackPushFailedPublicTopic("推送顺序异常,找不到有效推送配置", @event, order);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 是否自动推送
|
||||
if (!config.IsAutoPush)
|
||||
{
|
||||
TrackPushFailedPublicTopic("没有设置为自动推送,如果要推送请手动推送", @event, order);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 配置的类型如何和订单类型不一致则不允许推送
|
||||
if (config.OrderType != order.OrderType)
|
||||
{
|
||||
TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event,
|
||||
order);
|
||||
continue;
|
||||
}
|
||||
|
||||
var log = new TrackPushRecordIndex
|
||||
{
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
@ -196,6 +249,47 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||
CreateUser = GlobalConst.SystemUser,
|
||||
SubSystemCode = @event.SubSystemCode,
|
||||
IsToMq = @event.IsToMq,
|
||||
Extra = @event.SystemPushInfo.Extra
|
||||
};
|
||||
var item = await BuiltPushItem(config, log, @event.SystemPushInfo.CompareFields);
|
||||
item.Log = JsonConvert.SerializeObject(log);
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DoUpdateAsync(TrackPushEvent @event)
|
||||
{
|
||||
var config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode);
|
||||
if (config == null || !config.IsCanUpdate) return;
|
||||
|
||||
var items = new List<TrackUpdateInput>();
|
||||
foreach (var order in _orders)
|
||||
{
|
||||
//配置的类型如何和订单类型不一致则不允许推送
|
||||
if (config.OrderType != order.OrderType)
|
||||
{
|
||||
TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event,
|
||||
order);
|
||||
continue;
|
||||
}
|
||||
|
||||
var log = new TrackPushRecordIndex
|
||||
{
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
OrderId = order.Id,
|
||||
OrderNo = order.OrderNo,
|
||||
TrackStatus = @event.SystemPushInfo.TrackStatus,
|
||||
TrackCode = @event.TrackCode,
|
||||
TrackContent = @event.SystemPushInfo.TrackContent,
|
||||
TrackPlace = @event.SystemPushInfo.TrackPlace,
|
||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||
CreateUser = GlobalConst.SystemUser,
|
||||
SubSystemCode = @event.SubSystemCode,
|
||||
IsToMq = @event.IsToMq,
|
||||
Extra = @event.SystemPushInfo.Extra
|
||||
};
|
||||
var item = BuiltUpdateItem(config, log);
|
||||
item.Log = JsonConvert.SerializeObject(log);
|
||||
@ -208,14 +302,18 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode)))
|
||||
{
|
||||
var asciiString = Base64Helper.SerializeObject(OptionType.修改.ToString());
|
||||
var serviceProviderCode = _pushConfigs.First().ServiceProviderCode;
|
||||
var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
|
||||
_options.CurrentValue.TrackUpdateInterfaceCode,
|
||||
_pushConfigs.First().ServiceProviderCode, items, GlobalConst.TrackPushCompletedSubscribe,
|
||||
serviceProviderCode, items.Cast<object>().ToList(), GlobalConst.TrackPushCompletedSubscribe,
|
||||
attach: asciiString);
|
||||
|
||||
if (r.Code != GlobalConst.SuccessCode)
|
||||
{
|
||||
throw new BusinessException(message: $"requestId: {r.RequestId}; {r.Msg}");
|
||||
TrackPushFailedPublicTopic($"轨迹中台调用接口通失败,RequestId: {r.RequestId}; Msg: {r.Msg}", @event, r.RequestId,
|
||||
items.Cast<dynamic>().ToList());
|
||||
throw new BusinessException(
|
||||
message: $"requestId: {r.RequestId}; serviceProviderCode:{serviceProviderCode} Msg: {r.Msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,64 +323,120 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
var trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone);
|
||||
var trackDateStr = DateTimeFormat(trackDatetime, config.TrackTimeZone ?? log.TrackTimeZone, config);
|
||||
|
||||
var track = new TrackItem
|
||||
{
|
||||
// 推真实的发生地和发生时间(时间是计算后的)
|
||||
Location = log.TrackPlace,
|
||||
Date = trackDateStr,
|
||||
TimeZone = config.TrackTimeZone ?? log.TrackTimeZone,
|
||||
Description = config.TrackEnContentValue,
|
||||
DescriptionCn = config.TrackContentValue,
|
||||
Code = config.TrackContentCodeValue,
|
||||
Status = config.TrackStatusValue,
|
||||
Extra = config.ExpandFieldsValue
|
||||
};
|
||||
|
||||
var body = new TrackUpdateInput
|
||||
{
|
||||
OrderNo = log.OrderNo,
|
||||
OrderNo = log.OrderNo
|
||||
};
|
||||
body.Data.Add(track);
|
||||
var dict = new Dictionary<string, object?>()
|
||||
{
|
||||
//推真实的发生地和发生时间(时间是计算后的)
|
||||
{ "location", log.TrackPlace },
|
||||
{ "date", trackDateStr },
|
||||
{ "timeZone", config.TrackTimeZone ?? log.TrackTimeZone },
|
||||
{ "description", config.TrackEnContentValue },
|
||||
{ "descriptionCn", config.TrackContentValue },
|
||||
{ "code", config.TrackContentCodeValue },
|
||||
{ "status", config.TrackStatusValue },
|
||||
{ "extra", TextJsonHelper.Deserialize<object>(log.Extra) }
|
||||
};
|
||||
body.Data.Add(dict);
|
||||
log.PushContent = body.ToJson();
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
private async Task<TrackPushInput> BuiltPushItem(TrackPushContentConfigDto config, TrackPushRecordIndex log)
|
||||
private async Task<TrackPushInput> BuiltPushItem(TrackPushContentConfigDto config, TrackPushRecordIndex log,
|
||||
string? compareFields)
|
||||
{
|
||||
var trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone);
|
||||
var trackDateStr = DateTimeFormat(trackDatetime, config.TrackTimeZone ?? log.TrackTimeZone, config);
|
||||
|
||||
var track = new TrackItem
|
||||
{
|
||||
// 推真实的发生地和发生时间(时间是计算后的)
|
||||
Location = log.TrackPlace,
|
||||
Date = trackDateStr,
|
||||
TimeZone = config.TrackTimeZone ?? log.TrackTimeZone,
|
||||
Description = config.TrackEnContentValue,
|
||||
DescriptionCn = config.TrackContentValue,
|
||||
Code = config.TrackContentCodeValue,
|
||||
Status = config.TrackStatusValue,
|
||||
Extra = config.ExpandFieldsValue
|
||||
};
|
||||
|
||||
var body = new TrackPushInput
|
||||
{
|
||||
OrderNo = log.OrderNo,
|
||||
};
|
||||
body.Data.Add(track);
|
||||
var cur = new Dictionary<string, object?>
|
||||
{
|
||||
// 推真实的发生地和发生时间(时间是计算后的)
|
||||
{ "location", log.TrackPlace },
|
||||
{ "date", trackDateStr },
|
||||
{ "timeZone", config.TrackTimeZone ?? log.TrackTimeZone },
|
||||
{ "description", config.TrackEnContentValue },
|
||||
{ "descriptionCn", config.TrackContentValue },
|
||||
{ "code", config.TrackContentCodeValue },
|
||||
{ "status", config.TrackStatusValue },
|
||||
{ "extra", TextJsonHelper.Deserialize<object>(log.Extra) }
|
||||
};
|
||||
body.Data.Add(cur);
|
||||
|
||||
if (config.IsAllPush)
|
||||
{
|
||||
var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId);
|
||||
var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId, true);
|
||||
if (history != default)
|
||||
{
|
||||
body = JsonConvert.DeserializeObject<TrackPushInput>(history.PushContent);
|
||||
body!.Data.Add(track);
|
||||
body = TextJsonHelper.Deserialize<TrackPushInput>(history.PushContent);
|
||||
|
||||
//在推送历史中,选出当前轨迹明细一致的轨迹
|
||||
var tracks = await _trackDetailsEsRepository.GetListAsync(log.OrderId);
|
||||
//确定轨迹标识符
|
||||
var trackIdentifies = tracks.Select(x =>
|
||||
{
|
||||
//寻找映射配置(转换后的code)
|
||||
var code = _pushConfigs.First(y => y.TrackCode == x.TrackCode).TrackContentCodeValue;
|
||||
var timeStr = DateTimeFormat(x.TrackTime, config.TrackTimeZone ?? log.TrackTimeZone, config);
|
||||
return string.IsNullOrWhiteSpace(compareFields)
|
||||
? $"{code}{timeStr}"
|
||||
: $"{code}{TextJsonHelper.ExtractValue(x.Extra, compareFields)}";
|
||||
}
|
||||
).ToImmutableHashSet();
|
||||
//在历史中选取在订单当前轨迹明细中的记录
|
||||
body!.Data = body.Data.Where(x =>
|
||||
{
|
||||
var code = ((JsonElement) x["code"]!).GetString();
|
||||
var timeStr = ((JsonElement) x["date"]!).GetString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(compareFields))
|
||||
return trackIdentifies.Contains($"{code}{timeStr}");
|
||||
|
||||
if (((JsonElement) x["extra"]!).TryGetProperty(compareFields, out var comparerValueJsonElement))
|
||||
return trackIdentifies.Contains($"{code}{TextJsonHelper.GetString(comparerValueJsonElement)}");
|
||||
|
||||
return trackIdentifies.Contains($"{code}{null}");
|
||||
}).ToList();
|
||||
|
||||
|
||||
if (config.IsAllPushWithLatest)
|
||||
{
|
||||
//同code同比较字段保证唯一
|
||||
var old = body.Data
|
||||
.Where(x =>
|
||||
{
|
||||
//反序列化出的JsonElement和字典字符串类型做比较
|
||||
var a = ((JsonElement) x["code"]!).GetString();
|
||||
var b = cur["code"]!
|
||||
.ToString(); //tips: 需要要将object类型的字符串转为string类型,否则使用的是引用比较,反序列化出的string一定和本地string引用不同
|
||||
return a == b;
|
||||
})
|
||||
.WhereIf(!compareFields.IsNullOrWhiteSpace(), x =>
|
||||
{
|
||||
if (x["extra"] == null || log.Extra == null) return false;
|
||||
return TextJsonHelper.EqByJsonElementField(x["extra"]!,
|
||||
TextJsonHelper.Deserialize<JsonElement>(log.Extra), compareFields!);
|
||||
})
|
||||
.FirstOrDefault();
|
||||
|
||||
if (old != null)
|
||||
{
|
||||
body.Data.Remove(old);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加当前要推送的轨迹
|
||||
body.Data.Add(cur);
|
||||
}
|
||||
}
|
||||
|
||||
log.PushContent = body.ToJson();
|
||||
log.PushContent = TextJsonHelper.Serialize(body)!;
|
||||
|
||||
return body;
|
||||
}
|
||||
@ -291,35 +445,34 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
/// 根据轨迹代码推断下一个(升序)要推送的内容,如果找不到或者已经是最后一个了
|
||||
/// 则查询有没有可交换的推送,没有就返回null
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="latestPushTrackCode"></param>
|
||||
/// <param name="trackCode"></param>
|
||||
/// <returns></returns>
|
||||
TrackPushContentConfigDto? GetValidPushConfigAsync(List<TrackPushContentConfigDto> cache,
|
||||
string? latestPushTrackCode, string? trackCode)
|
||||
private static TrackPushContentConfigDto? GetValidPushConfigAsync(List<TrackPushContentConfigDto> cache,
|
||||
string? latestPushTrackCode, TrackPushEvent @event)
|
||||
{
|
||||
var trackCode = @event.TrackCode;
|
||||
var idx = cache.FindIndex(x => x.TrackCode == latestPushTrackCode);
|
||||
|
||||
if (@event.ForcedPush && trackCode == latestPushTrackCode)
|
||||
{
|
||||
//强制推送,允许重复推送当前轨迹
|
||||
return cache[idx];
|
||||
}
|
||||
|
||||
if (idx + 1 >= cache.Count) return default; // 推完了
|
||||
|
||||
// find next
|
||||
var matched = cache[idx + 1].TrackCode == trackCode
|
||||
? cache[idx + 1]
|
||||
:
|
||||
// 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 : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换推送时间格式
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <param name="timezone"></param>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
private string DateTimeFormat(DateTime dateTime, double timezone, TrackPushContentConfigDto config)
|
||||
private static string DateTimeFormat(DateTime dateTime, double timezone, TrackPushContentConfigDto config)
|
||||
{
|
||||
if (config.DateTimeFormatType == (int) DateTimeFormatEnum.Timestamp)
|
||||
return DateTimeHelper.ConvertToUnixTimestamp(dateTime).ToString();
|
||||
@ -335,4 +488,61 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
||||
|
||||
return dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK");
|
||||
}
|
||||
|
||||
//轨迹推送失败(被拦截)
|
||||
private void TrackPushFailedPublicTopic(string failedMessage, TrackPushEvent @event, OrderEntity order)
|
||||
{
|
||||
_broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto
|
||||
{
|
||||
//还没请求接口通
|
||||
RequestId = null,
|
||||
IsSuccess = false,
|
||||
Message = failedMessage,
|
||||
OperationMan = @event.OperationMan,
|
||||
PushTime = DateTime.Now,
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
IsManualPush = @event.OperationMan != null,
|
||||
//还没到构建推送内容那一步就被拦截
|
||||
PushContent = string.Empty,
|
||||
OrderNo = order.OrderNo,
|
||||
TrackStatus = @event.SystemPushInfo.TrackStatus,
|
||||
TrackContent = @event.SystemPushInfo.TrackStatus,
|
||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||
TrackPlace = @event.SystemPushInfo.TrackPlace,
|
||||
TrackCode = @event.TrackCode,
|
||||
Extra = @event.SystemPushInfo.Extra,
|
||||
});
|
||||
}
|
||||
|
||||
//轨迹推送失败(请求接口通)
|
||||
private void TrackPushFailedPublicTopic(
|
||||
string failedMessage,
|
||||
TrackPushEvent @event,
|
||||
Guid requestId,
|
||||
List<dynamic> pushOrUpdateInputs)
|
||||
{
|
||||
foreach (var pushInput in pushOrUpdateInputs)
|
||||
{
|
||||
_broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto
|
||||
{
|
||||
RequestId = requestId,
|
||||
IsSuccess = false,
|
||||
Message = failedMessage,
|
||||
OperationMan = @event.OperationMan,
|
||||
PushTime = DateTime.Now,
|
||||
OptionType = @event.OptionType.ToString(),
|
||||
IsManualPush = @event.OperationMan != null,
|
||||
PushContent = TextJsonHelper.Serialize(pushInput),
|
||||
OrderNo = pushInput.OrderNo,
|
||||
TrackStatus = @event.SystemPushInfo.TrackStatus,
|
||||
TrackContent = @event.SystemPushInfo.TrackStatus,
|
||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||
TrackPlace = @event.SystemPushInfo.TrackPlace,
|
||||
TrackCode = @event.TrackCode,
|
||||
Extra = @event.SystemPushInfo.Extra,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
using System.Text;
|
||||
using BSI.Stack.Rabbit;
|
||||
using System.Diagnostics;
|
||||
using DotNetCore.CAP;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SJZY.Expand.ABP.Core.Logger;
|
||||
using SJZY.Expand.ABP.Core.PublicMethords;
|
||||
using SJZY.Track.Application.Contract.Events;
|
||||
using SJZY.Track.Application.Contract.Services;
|
||||
using SJZY.Track.Application.Helpers;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
||||
using SJZY.Track.Domain.Dtos.TrackContents;
|
||||
using SJZY.Track.Domain.Enums;
|
||||
using SJZY.Track.Domain.Queries;
|
||||
@ -21,7 +22,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly IProvideQueries _provideQueries;
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
private readonly RabbitClientBus _rabbitClientBus;
|
||||
private readonly IBroadcastingService _broadcastingService;
|
||||
private readonly ILogger<TrackUpsertEventHandler> _logger;
|
||||
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
||||
|
||||
public TrackUpsertEventHandler(
|
||||
@ -29,15 +31,17 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
ICapPublisher capPublisher,
|
||||
IProvideQueries provideQueries,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||
RabbitClientBus rabbitClientBus,
|
||||
IOrderOperationRecordEsRepository orderOperationRecordEsRepository)
|
||||
IOrderOperationRecordEsRepository orderOperationRecordEsRepository,
|
||||
IBroadcastingService broadcastingService,
|
||||
ILogger<TrackUpsertEventHandler> logger)
|
||||
{
|
||||
_orderRepository = orderRepository;
|
||||
_capPublisher = capPublisher;
|
||||
_provideQueries = provideQueries;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
_rabbitClientBus = rabbitClientBus;
|
||||
_orderOperationRecordEsRepository = orderOperationRecordEsRepository;
|
||||
_broadcastingService = broadcastingService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)]
|
||||
@ -51,59 +55,14 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
var content = await HandleTrackAsync(@event, canNextOrderIds);
|
||||
|
||||
// 处理广播事件
|
||||
PublicTrackTopic(@event, content);
|
||||
if (content != null && (content.IsToMq || @event.IsToMq))
|
||||
_ = EnsureWriteAfterPublicTopicAsync(@event, content.SubSystemCode, content.TrackStatusCode);
|
||||
|
||||
if (canNextOrderIds.Count == 0) return;
|
||||
// 根据订单关联关系异步向下刷(异步)
|
||||
await DownByOrderLink(@event, canNextOrderIds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送轨迹广播
|
||||
/// </summary>
|
||||
/// <param name="eto"></param>
|
||||
/// <param name="content"></param>
|
||||
private void PublicTrackTopic(TrackUpsertEvent eto, TrackContentVO? content)
|
||||
{
|
||||
// var trackStatus = await _trackStatusRepository.GetFirstAsync(m => m.Code == content.TrackStatusCode);
|
||||
if (content == null || !content.IsToMq)
|
||||
return;
|
||||
|
||||
var data = new TrackChangeEto()
|
||||
{
|
||||
EstimatedDeliveryDate = eto.EstimatedDeliveryDate,
|
||||
TrackPlacePostcode = eto.TrackPlacePostcode,
|
||||
TrackPlaceNation = eto.TrackPlaceNation,
|
||||
TrackPlaceNationId = eto.TrackPlaceNationId,
|
||||
TrackPlaceProvince = eto.TrackPlaceProvince,
|
||||
TrackPlaceProvinceId = eto.TrackPlaceProvinceId,
|
||||
TrackPlaceCity = eto.TrackPlaceCity,
|
||||
TrackPlaceCityId = eto.TrackPlaceCityId,
|
||||
Files = eto.Files,
|
||||
Remarks = eto.Remarks,
|
||||
Source = eto.Source,
|
||||
IsVisibility = eto.IsVisibility,
|
||||
TrackTimeZone = eto.TrackTimeZone,
|
||||
TrackTime = eto.TrackTime,
|
||||
TrackPlace = eto.TrackPlace,
|
||||
TrackStatusCode = content.TrackStatusCode,
|
||||
EnStatus = eto.EnStatus,
|
||||
Content = eto.Content,
|
||||
TrackCode = eto.TrackCode,
|
||||
OperationMan = eto.OperationMan,
|
||||
OrderIdentifiers = eto.OrderIdentifiers,
|
||||
CustomId = eto.CustomId,
|
||||
SubSystemId = eto.SubSystemId
|
||||
};
|
||||
|
||||
if (eto.IsAdd)
|
||||
data.Option = 1;
|
||||
else
|
||||
data.Option = 3;
|
||||
|
||||
_rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{content.SubSystemCode}", Encoding.UTF8.GetBytes(data.ToJson()));
|
||||
}
|
||||
|
||||
private async Task DownByOrderLink(TrackUpsertEvent @event, List<int> canNextOrderIds)
|
||||
{
|
||||
// 根据订单关联关系异步向下刷(异步)
|
||||
@ -185,6 +144,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
return false;
|
||||
}
|
||||
|
||||
// todo: 在这里,判断存在性
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -217,6 +178,14 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
// 批量add to es
|
||||
await _trackDetailsEsRepository.AddManyAsync(insertTracks);
|
||||
|
||||
//批量写入订单操作日志
|
||||
_ = _orderOperationRecordEsRepository
|
||||
.AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier
|
||||
{
|
||||
OrderNo = t.OrderNo,
|
||||
OrderId = t.OrderId
|
||||
})).ToList());
|
||||
|
||||
// 添加轨迹触发订单拉取状态更新
|
||||
await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(),
|
||||
@event.TrackCode);
|
||||
@ -262,8 +231,12 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
TrackContent = trackContent.TrackContent,
|
||||
TrackPlace = @event.TrackPlace,
|
||||
TrackTime = @event.NewTrackTime ?? @event.TrackTime,
|
||||
TrackTimeZone = @event.TrackTimeZone
|
||||
}
|
||||
TrackTimeZone = @event.TrackTimeZone,
|
||||
CompareFields = @event.CompareFields,
|
||||
Extra = @event.Extra
|
||||
},
|
||||
ForcedPush = @event.ForcedPush,
|
||||
IsToMq = (trackContent.IsToMq || @event.IsToMq)
|
||||
};
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent);
|
||||
|
||||
@ -276,180 +249,76 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray();
|
||||
|
||||
// important:轨迹code相同,时间、发生地不同的,可能存在多条!!
|
||||
var tracks = await _trackDetailsEsRepository.GetListAsync(orderIds, @event.TrackCode, false);
|
||||
var tracks = await _trackDetailsEsRepository.GetListAsync(orderIds, @event.TrackCode, true);
|
||||
|
||||
var insertTracks = new List<TrackDetailsIndex>();
|
||||
var updateTracks = new List<TrackDetailsIndex>();
|
||||
|
||||
var operationRecords = new List<OrderOperationRecordIndex>();
|
||||
foreach (var order in @event.OrderIdentifiers)
|
||||
{
|
||||
TrackDetailsIndex? track;
|
||||
if (!@event.IsAdd)
|
||||
// fast path: by update with es id case
|
||||
if (!@event.IsAdd && !string.IsNullOrWhiteSpace(@event.EsId))
|
||||
{
|
||||
//同一订单同轨迹code同一轨迹时间如果有多条轨迹明细则不允许修改
|
||||
var existTracks = tracks.Where(x => x.OrderId == order.OrderId
|
||||
&& x.TrackTime == @event.TrackTime).ToArray();
|
||||
if (existTracks.Length > 1)
|
||||
var trackById = tracks.FirstOrDefault(x => x.Id == @event.EsId);
|
||||
if (trackById != null)
|
||||
{
|
||||
// 修改轨迹时,订单存在多条轨迹不允许修改
|
||||
continue;
|
||||
updateTracks.Add(BuiltUpdateTrack(@event, trackById, order, trackContent));
|
||||
}
|
||||
|
||||
track = existTracks.FirstOrDefault();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (track == null) continue; // 不存在不让改
|
||||
var existTracks = tracks.Where(x => x.OrderId == order.OrderId).ToList();
|
||||
|
||||
if (@event.CompareFields.IsNullOrEmpty())
|
||||
{
|
||||
existTracks = existTracks.Where(x => x.TrackTime == @event.TrackTime).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 【批量新增】所有可能遇到的场景
|
||||
// 标识:允许重复,不允许重复,零条,一条,多条;
|
||||
// 场景A:允许重复,零条 => 新增
|
||||
// 场景B:允许重复,一条 => 新增(约束受限新增,否则跳过新增)
|
||||
// 场景C:允许重复,多条 => 新增(约束受限新增,否则跳过新增)
|
||||
// 场景D:不允许重复,零条 => 新增
|
||||
// 场景E:不允许重复,一条 => 跳过
|
||||
// 场景F:不允许重复,(理想不会出现多条) => 跳过
|
||||
var existTracks = tracks.Where(x => x.OrderId == order.OrderId).ToArray();
|
||||
track = existTracks.FirstOrDefault();
|
||||
|
||||
//覆盖场景:B,C
|
||||
if (trackContent.IsRepeatable && existTracks.Length >= 1)
|
||||
Debug.Assert(@event.CompareFields != null, "@event.CompareFields != null");
|
||||
var extraDict = TextJsonHelper.DeserializeToDictionary(@event.Extra);
|
||||
if (extraDict == null || !extraDict.TryGetValue(@event.CompareFields, out var compareValue))
|
||||
{
|
||||
if (existTracks.Any(x => x.TrackPlace == @event.TrackPlace && x.TrackTime == @event.TrackTime))
|
||||
throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{@event.CompareFields}");
|
||||
}
|
||||
|
||||
existTracks = existTracks.Where(x =>
|
||||
{
|
||||
var oldExtraDict = TextJsonHelper.DeserializeToDictionary(x.Extra);
|
||||
// tips:注意兼容性,历史轨迹的字段可能为空
|
||||
if (oldExtraDict == null || !oldExtraDict.TryGetValue(@event.CompareFields, out var oldValue))
|
||||
{
|
||||
//允许重复,出现【轨迹发生地】,【轨迹发生时间】的都重复,则不允许新增
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置null后面执行新增逻辑
|
||||
track = null;
|
||||
}
|
||||
return TextJsonHelper.EqJsonElement(oldValue, compareValue);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
//不允许重复,并且记录大于等于一条,跳过
|
||||
//覆盖场景:E,F
|
||||
if (!trackContent.IsRepeatable && existTracks.Length >= 1)
|
||||
var track = existTracks.FirstOrDefault();
|
||||
|
||||
if (!@event.IsAdd)
|
||||
{
|
||||
if (existTracks.Count > 1)
|
||||
{
|
||||
// todo: 所有的event handle 多写log,取缔注释,特别是continue,return,这种跳出的地方,方便排查问题
|
||||
_logger.LogInformation("订单存在多条轨迹不允许修改:{@event}", @event);
|
||||
continue;
|
||||
}
|
||||
|
||||
//其余情况:A,D都为新增操作,无需检查数量,track为null执行新增操作
|
||||
}
|
||||
// todo:例如这里
|
||||
if (track == null) continue; // 不存在不让改
|
||||
|
||||
if (track == default)
|
||||
{
|
||||
track = new TrackDetailsIndex
|
||||
{
|
||||
SubSystemId = @event.SubSystemId,
|
||||
OrderId = order.OrderId,
|
||||
OrderNo = order.OrderNo,
|
||||
OrderType = order.OrderType,
|
||||
TrackCode = @event.TrackCode,
|
||||
TrackPlace = @event.TrackPlace,
|
||||
TrackTime = @event.NewTrackTime ?? @event.TrackTime,
|
||||
TrackTimeZone = @event.TrackTimeZone,
|
||||
ServiceProviderCode = @event.TrackRefreshData.ServiceProviderCode ?? GlobalConst.EmptyString,
|
||||
OriginTrackContent = @event.TrackRefreshData.OriginTrackContent ?? GlobalConst.EmptyString,
|
||||
OriginTrackDataHash = @event.TrackRefreshData.OriginTrackDataHash ?? GlobalConst.EmptyString,
|
||||
CreateUser = @event.OperationMan ?? GlobalConst.SystemUser,
|
||||
CreateTime = DateTime.Now,
|
||||
//来源轨迹内容,第一次新增的时候使用轨迹内容表提供的
|
||||
TrackStatusId = trackContent.TrackStatusId,
|
||||
TrackStatus = trackContent.TrackStatus,
|
||||
TrackStatusCode = trackContent.TrackStatusCode,
|
||||
//跨子系统?
|
||||
TrackContentId = trackContent.TrackContentId,
|
||||
TrackContent = @event.Content ?? trackContent.TrackContent,
|
||||
TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent,
|
||||
//S06新增轨迹明细字段
|
||||
IsVisibility = @event.IsVisibility,
|
||||
Source = @event.Source,
|
||||
Remarks = @event.Remarks ?? GlobalConst.EmptyString,
|
||||
Files = @event.Files?.Select(x => new FileItem
|
||||
{
|
||||
OssKey = x.OssKey,
|
||||
FileName = x.FileName
|
||||
}).ToList(),
|
||||
TrackPlaceCity = @event.TrackPlaceCity ?? GlobalConst.EmptyString,
|
||||
TrackPlaceCityId = @event.TrackPlaceCityId ?? GlobalConst.NotExistId,
|
||||
TrackPlaceProvince = @event.TrackPlaceProvince ?? GlobalConst.EmptyString,
|
||||
TrackPlaceProvinceId = @event.TrackPlaceProvinceId ?? GlobalConst.NotExistId,
|
||||
TrackPlaceNation = @event.TrackPlaceNation ?? GlobalConst.EmptyString,
|
||||
TrackPlaceNationId = @event.TrackPlaceNationId ?? GlobalConst.NotExistId,
|
||||
TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString,
|
||||
DestinationTimeZone = @event.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = @event.EstimatedDeliveryDate,
|
||||
Extra = @event.Extra
|
||||
};
|
||||
|
||||
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
|
||||
? track.TrackTime
|
||||
: track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
|
||||
insertTracks.Add(track);
|
||||
|
||||
// 写入操作日志
|
||||
_ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex
|
||||
{
|
||||
OrderId = order.OrderId,
|
||||
OrderNo = order.OrderNo,
|
||||
OptionType = OrderOperationType.创建轨迹.ToString(),
|
||||
Content = track.ToJson(),
|
||||
CreateUserId = @event.OperationManId,
|
||||
CreateUserName = @event.OperationMan ?? "",
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
updateTracks.Add(BuiltUpdateTrack(@event, track, order, trackContent));
|
||||
operationRecords.Add(BuildOrderOperationRecord(@event, track, order));
|
||||
}
|
||||
else
|
||||
{
|
||||
//外部轨迹,轨迹发生地,轨迹发生时间,轨迹发生时区,不允许更改
|
||||
if (track.Source != (int) TrackSourceEnum.ExternalServiceProvide)
|
||||
{
|
||||
track.TrackPlace = @event.TrackPlace;
|
||||
track.TrackTime = @event.NewTrackTime ?? @event.TrackTime;
|
||||
track.TrackTimeZone = @event.TrackTimeZone;
|
||||
}
|
||||
// 不允许重复轨迹,跳过
|
||||
if (!trackContent.IsRepeatable && existTracks.Count > 0) continue;
|
||||
|
||||
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
|
||||
? track.TrackTime
|
||||
: track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
|
||||
track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser;
|
||||
track.UpdateTime = DateTime.Now;
|
||||
|
||||
//允许二次修改,在修改了轨迹内容后进行修改轨迹操作,如果输入的轨迹内容则以输入为准
|
||||
//跨子系统?
|
||||
track.TrackContent = @event.Content ?? trackContent.TrackContent;
|
||||
track.TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent;
|
||||
//S06新增
|
||||
track.IsVisibility = @event.IsVisibility;
|
||||
track.Remarks = @event.Remarks ?? GlobalConst.EmptyString;
|
||||
track.Files = @event.Files?.Select(x => new FileItem
|
||||
{
|
||||
OssKey = x.OssKey,
|
||||
FileName = x.FileName
|
||||
}).ToList();
|
||||
track.TrackPlaceCity = @event.TrackPlaceCity ?? GlobalConst.EmptyString;
|
||||
track.TrackPlaceCityId = @event.TrackPlaceCityId ?? GlobalConst.NotExistId;
|
||||
track.TrackPlaceProvince = @event.TrackPlaceProvince ?? GlobalConst.EmptyString;
|
||||
track.TrackPlaceProvinceId = @event.TrackPlaceProvinceId ?? GlobalConst.NotExistId;
|
||||
track.TrackPlaceNation = @event.TrackPlaceNation ?? GlobalConst.EmptyString;
|
||||
track.TrackPlaceNationId = @event.TrackPlaceNationId ?? GlobalConst.NotExistId;
|
||||
track.TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString;
|
||||
track.DestinationTimeZone = @event.DestinationTimeZone;
|
||||
track.EstimatedDeliveryDate = @event.EstimatedDeliveryDate;
|
||||
track.Extra = @event.Extra;
|
||||
|
||||
updateTracks.Add(track);
|
||||
|
||||
// 写入操作日志
|
||||
_ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex
|
||||
{
|
||||
OrderId = order.OrderId,
|
||||
OrderNo = order.OrderNo,
|
||||
OptionType = OrderOperationType.修改轨迹.ToString(),
|
||||
Content = track.ToJson(),
|
||||
CreateUserId = @event.OperationManId,
|
||||
CreateUserName = @event.OperationMan ?? "",
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
insertTracks.Add(BuiltNewTrack(@event, order, trackContent));
|
||||
}
|
||||
|
||||
canNextOrderIds.Add(order.OrderId);
|
||||
@ -459,8 +328,133 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
||||
{
|
||||
//批量差异化更新轨迹
|
||||
await _trackDetailsEsRepository.BulkUpdateAsync(updateTracks);
|
||||
//批量写入操作日志
|
||||
_ = _orderOperationRecordEsRepository.AddManyAsync(operationRecords);
|
||||
}
|
||||
|
||||
return insertTracks;
|
||||
}
|
||||
|
||||
|
||||
private TrackDetailsIndex BuiltUpdateTrack(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order,
|
||||
TrackContentVO trackContent)
|
||||
{
|
||||
//外部轨迹,轨迹发生地,轨迹发生时间,轨迹发生时区,不允许更改
|
||||
if (track.Source != (int) TrackSourceEnum.ExternalServiceProvide)
|
||||
{
|
||||
track.TrackPlace = @event.TrackPlace;
|
||||
track.TrackTime = @event.NewTrackTime ?? @event.TrackTime;
|
||||
track.TrackTimeZone = @event.TrackTimeZone;
|
||||
}
|
||||
|
||||
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
|
||||
? track.TrackTime
|
||||
: track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
|
||||
track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser;
|
||||
track.UpdateTime = DateTime.Now;
|
||||
|
||||
//允许二次修改,在修改了轨迹内容后进行修改轨迹操作,如果输入的轨迹内容则以输入为准
|
||||
//跨子系统?
|
||||
track.TrackContent = @event.Content ?? trackContent.TrackContent;
|
||||
track.TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent;
|
||||
//S06新增
|
||||
track.IsVisibility = @event.IsVisibility;
|
||||
track.Remarks = @event.Remarks ?? GlobalConst.EmptyString;
|
||||
track.Files = @event.Files?.Select(x => new FileItem
|
||||
{
|
||||
OssKey = x.OssKey,
|
||||
FileName = x.FileName
|
||||
}).ToList();
|
||||
track.TrackPlaceCity = @event.TrackPlaceCity ?? GlobalConst.EmptyString;
|
||||
track.TrackPlaceCityId = @event.TrackPlaceCityId ?? GlobalConst.NotExistId;
|
||||
track.TrackPlaceProvince = @event.TrackPlaceProvince ?? GlobalConst.EmptyString;
|
||||
track.TrackPlaceProvinceId = @event.TrackPlaceProvinceId ?? GlobalConst.NotExistId;
|
||||
track.TrackPlaceNation = @event.TrackPlaceNation ?? GlobalConst.EmptyString;
|
||||
track.TrackPlaceNationId = @event.TrackPlaceNationId ?? GlobalConst.NotExistId;
|
||||
track.TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString;
|
||||
track.DestinationTimeZone = @event.DestinationTimeZone;
|
||||
track.EstimatedDeliveryDate = @event.EstimatedDeliveryDate;
|
||||
track.Extra = @event.Extra;
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
private TrackDetailsIndex BuiltNewTrack(TrackUpsertEvent @event, OrderIdentifier order, TrackContentVO trackContent)
|
||||
{
|
||||
var track = new TrackDetailsIndex
|
||||
{
|
||||
SubSystemId = @event.SubSystemId,
|
||||
OrderId = order.OrderId,
|
||||
OrderNo = order.OrderNo,
|
||||
OrderType = order.OrderType,
|
||||
TrackCode = @event.TrackCode,
|
||||
TrackPlace = @event.TrackPlace,
|
||||
TrackTime = @event.NewTrackTime ?? @event.TrackTime,
|
||||
TrackTimeZone = @event.TrackTimeZone,
|
||||
ServiceProviderCode = @event.TrackRefreshData.ServiceProviderCode ?? GlobalConst.EmptyString,
|
||||
OriginTrackContent = @event.TrackRefreshData.OriginTrackContent ?? GlobalConst.EmptyString,
|
||||
OriginTrackDataHash = @event.TrackRefreshData.OriginTrackDataHash ?? GlobalConst.EmptyString,
|
||||
CreateUser = @event.OperationMan ?? GlobalConst.SystemUser,
|
||||
CreateTime = DateTime.Now,
|
||||
//来源轨迹内容,第一次新增的时候使用轨迹内容表提供的
|
||||
TrackStatusId = trackContent.TrackStatusId,
|
||||
TrackStatus = trackContent.TrackStatus,
|
||||
TrackStatusCode = trackContent.TrackStatusCode,
|
||||
//跨子系统?
|
||||
TrackContentId = trackContent.TrackContentId,
|
||||
TrackContent = @event.Content ?? trackContent.TrackContent,
|
||||
TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent,
|
||||
//S06新增轨迹明细字段
|
||||
IsVisibility = @event.IsVisibility,
|
||||
Source = @event.Source,
|
||||
Remarks = @event.Remarks ?? GlobalConst.EmptyString,
|
||||
Files = @event.Files?.Select(x => new FileItem
|
||||
{
|
||||
OssKey = x.OssKey,
|
||||
FileName = x.FileName
|
||||
}).ToList(),
|
||||
TrackPlaceCity = @event.TrackPlaceCity ?? GlobalConst.EmptyString,
|
||||
TrackPlaceCityId = @event.TrackPlaceCityId ?? GlobalConst.NotExistId,
|
||||
TrackPlaceProvince = @event.TrackPlaceProvince ?? GlobalConst.EmptyString,
|
||||
TrackPlaceProvinceId = @event.TrackPlaceProvinceId ?? GlobalConst.NotExistId,
|
||||
TrackPlaceNation = @event.TrackPlaceNation ?? GlobalConst.EmptyString,
|
||||
TrackPlaceNationId = @event.TrackPlaceNationId ?? GlobalConst.NotExistId,
|
||||
TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString,
|
||||
DestinationTimeZone = @event.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = @event.EstimatedDeliveryDate,
|
||||
Extra = @event.Extra
|
||||
};
|
||||
|
||||
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
|
||||
? track.TrackTime
|
||||
: track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
private OrderOperationRecordIndex BuildOrderOperationRecord(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order)
|
||||
{
|
||||
return new OrderOperationRecordIndex
|
||||
{
|
||||
OrderId = order.OrderId,
|
||||
OrderNo = order.OrderNo,
|
||||
OptionType = @event.IsAdd ? OrderOperationType.创建轨迹.ToString() : OrderOperationType.修改轨迹.ToString(),
|
||||
Content = track.ToJson(),
|
||||
CreateUserId = @event.OperationManId,
|
||||
CreateUserName = @event.OperationMan ?? "",
|
||||
CreateTime = DateTime.Now
|
||||
};
|
||||
}
|
||||
|
||||
private async Task EnsureWriteAfterPublicTopicAsync(TrackUpsertEvent @event, string subSystemCode, string statusCode)
|
||||
{
|
||||
//理想情况在写入之后1s会刷盘 https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html
|
||||
//增加一个版本号来确定是否真的变更了
|
||||
//没有刷盘成功事件回调
|
||||
//方案1:!!【轮询等待静默刷盘】查出版本号确实发生了变更在发送广播
|
||||
//方案2:考虑强制刷盘(对es压力大)后发送
|
||||
//方案3:采用一个较大延时,不查询直接发
|
||||
await Task.Delay(1000);
|
||||
_broadcastingService.TrackChangePublicTopic(@event, subSystemCode, statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
181
src/SJZY.Track.Application/Helpers/TextJsonHelper.cs
Normal file
181
src/SJZY.Track.Application/Helpers/TextJsonHelper.cs
Normal file
@ -0,0 +1,181 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SJZY.Track.Application.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 针对 Text.Json 的一些辅助方法
|
||||
/// </summary>
|
||||
public static class TextJsonHelper
|
||||
{
|
||||
public static string? Serialize(object? obj)
|
||||
{
|
||||
return obj == null ? default : System.Text.Json.JsonSerializer.Serialize(obj);
|
||||
}
|
||||
|
||||
public static T? Deserialize<T>(string? json)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(json) ? default : System.Text.Json.JsonSerializer.Deserialize<T>(json);
|
||||
}
|
||||
|
||||
public static Dictionary<string, object?>? DeserializeToDictionary(string? dictJsonString)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(dictJsonString)
|
||||
? null
|
||||
: System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(dictJsonString);
|
||||
}
|
||||
|
||||
public static JsonElement? DeserializeToJsonElement(string? dictJsonString)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(dictJsonString)
|
||||
? null
|
||||
: System.Text.Json.JsonSerializer.Deserialize<JsonElement>(dictJsonString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取JsonElement字符串表达的值
|
||||
/// </summary>
|
||||
/// <param name="el"></param>
|
||||
/// <returns></returns>
|
||||
public static string? GetString(object? el)
|
||||
{
|
||||
if (el is not JsonElement jsonElement)
|
||||
return default;
|
||||
return jsonElement.ValueKind switch
|
||||
{
|
||||
JsonValueKind.Undefined or JsonValueKind.Null => default,
|
||||
JsonValueKind.True or JsonValueKind.False => jsonElement.GetBoolean().ToString(),
|
||||
JsonValueKind.Object or JsonValueKind.Array or JsonValueKind.Number => jsonElement.GetRawText(),
|
||||
JsonValueKind.String => jsonElement.GetString(),
|
||||
_ => default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提取字典字符串中某个字段的值
|
||||
/// </summary>
|
||||
/// <param name="dictString">字典json字符串</param>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public static object? ExtractValue(string? dictString, string fieldName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(dictString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(dictString);
|
||||
if (dict == null || !dict.TryGetValue(fieldName, out var value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 两个jsonElement进行比较
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
public static bool EqJsonElement(object? a, object? b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a is JsonElement aJsonElement && b is JsonElement bJsonElement)
|
||||
{
|
||||
return aJsonElement.ToString() == bJsonElement.ToString();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// jsonElement和object之间的比较
|
||||
/// </summary>
|
||||
/// <param name="jsonElement"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static bool EqJsonElementAndObject(object? jsonElement, object? obj)
|
||||
{
|
||||
if (jsonElement == null && obj == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (jsonElement is JsonElement aJsonElement)
|
||||
{
|
||||
switch (aJsonElement.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Undefined:
|
||||
return false;
|
||||
case JsonValueKind.Object:
|
||||
return false;
|
||||
case JsonValueKind.Array:
|
||||
return false;
|
||||
case JsonValueKind.String:
|
||||
return string.Equals(aJsonElement.GetString(), obj as string);
|
||||
case JsonValueKind.Number:
|
||||
{
|
||||
if (obj == null) return false;
|
||||
|
||||
if (obj is int bInt)
|
||||
{
|
||||
var aInt = aJsonElement.GetInt32();
|
||||
return aInt == bInt;
|
||||
}
|
||||
|
||||
if (obj is long bLong)
|
||||
{
|
||||
var aLong = aJsonElement.GetInt64();
|
||||
return aLong == bLong;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
case JsonValueKind.True:
|
||||
case JsonValueKind.False:
|
||||
{
|
||||
if (obj is bool bl)
|
||||
{
|
||||
return aJsonElement.GetBoolean() == bl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
case JsonValueKind.Null:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个jsonElement中的的fieldName字段的值
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public static bool EqByJsonElementField(object? a, object? b, string fieldName)
|
||||
{
|
||||
if (a is not JsonElement aJsonElement || b is not JsonElement bJsonElement)
|
||||
return false;
|
||||
|
||||
if (aJsonElement.TryGetProperty(fieldName, out var aValue)
|
||||
&& bJsonElement.TryGetProperty(fieldName, out var bValue))
|
||||
{
|
||||
return aValue.ToString() == bValue.ToString();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -57,6 +57,16 @@ public class InterfaceRelayParamsConfigOptions
|
||||
/// </summary>
|
||||
public string PushTrackInterfaceCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送轨迹接口Id
|
||||
/// </summary>
|
||||
public int PushTrackInterfaceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送轨迹接口 内容项 参数别名前缀
|
||||
/// </summary>
|
||||
public string PushTrackItemParamAliasPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新轨迹接口代码
|
||||
/// </summary>
|
||||
|
||||
@ -6,6 +6,7 @@ using RabbitMQ.Client.Events;
|
||||
using SJZY.Expand.ABP.Core.Logger;
|
||||
using SJZY.InterfaceRelay.Application.Contracts;
|
||||
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||
using SJZY.Track.Application.Contract.Services;
|
||||
using SJZY.Track.Application.Helpers;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
|
||||
@ -18,12 +19,15 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
||||
{
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
||||
private readonly IBroadcastingService _broadcastingService;
|
||||
|
||||
public TrackPushCompletedEventHandler(IOrderRepository orderRepository,
|
||||
ITrackPushRecordEsRepository trackPushRecordEsRepository)
|
||||
ITrackPushRecordEsRepository trackPushRecordEsRepository,
|
||||
IBroadcastingService broadcastingService)
|
||||
{
|
||||
_orderRepository = orderRepository;
|
||||
_trackPushRecordEsRepository = trackPushRecordEsRepository;
|
||||
_broadcastingService = broadcastingService;
|
||||
}
|
||||
|
||||
public ConsumeOptions Options()
|
||||
@ -49,11 +53,11 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
||||
var optionType = Base64Helper.DeSerialize<string>(@event.Attach);
|
||||
if (optionType == OptionType.新增.ToString())
|
||||
{
|
||||
logStr = JsonConvert.DeserializeObject<TrackPushInput>(@event.RequestParams)!.Log;
|
||||
logStr = JsonConvert.DeserializeObject<List<TrackPushInput>>(@event.RequestParams)!.First().Log;
|
||||
}
|
||||
else if (optionType == OptionType.修改.ToString())
|
||||
{
|
||||
logStr = JsonConvert.DeserializeObject<TrackUpdateInput>(@event.RequestParams)!.Log;
|
||||
logStr = JsonConvert.DeserializeObject<List<TrackUpdateInput>>(@event.RequestParams)!.First().Log;
|
||||
}
|
||||
|
||||
if (logStr.IsNullOrEmpty()) throw new InvalidOperationException();
|
||||
@ -64,6 +68,10 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
||||
log.Message = @event.Message;
|
||||
log.RequestId = @event.RequestId;
|
||||
|
||||
// 推送广播
|
||||
if (log.IsToMq)
|
||||
_broadcastingService.TrackPushCompletedPublicTopic(BuildDto(log));
|
||||
|
||||
// 往es 写推送日志
|
||||
await _trackPushRecordEsRepository.AddAsync(log);
|
||||
|
||||
@ -111,4 +119,28 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private TrackPushRecordDto BuildDto(TrackPushRecordIndex log)
|
||||
{
|
||||
return new TrackPushRecordDto
|
||||
{
|
||||
SubSystemCode = log.SubSystemCode,
|
||||
RequestId = log.RequestId,
|
||||
IsSuccess = log.IsSuccess,
|
||||
Message = log.Message,
|
||||
OperationMan = log.CreateUser,
|
||||
PushTime = DateTime.Now,
|
||||
OptionType = log.OptionType,
|
||||
IsManualPush = !string.Equals(log.CreateUser, GlobalConst.SystemUser), //操作人不为系统用户,则认为是仍推送
|
||||
PushContent = log.PushContent,
|
||||
OrderNo = log.OrderNo,
|
||||
TrackStatus = log.TrackStatus,
|
||||
TrackContent = log.TrackContent,
|
||||
TrackTimeZone = log.TrackTimeZone,
|
||||
TrackTime = log.TrackTime,
|
||||
TrackPlace = log.TrackPlace,
|
||||
TrackCode = log.TrackCode,
|
||||
Extra = log.Extra
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<PackageReference Include="BSI.Stack.Rabbit" Version="2.1.3" />
|
||||
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue" Version="8.2.1"/>
|
||||
<PackageReference Include="SJZY.Expand.AliyunOSS" Version="7.0.17" />
|
||||
<PackageReference Include="SJZY.InterfaceRelay.Application.Contracts" Version="7.2.5-alpha" />
|
||||
<PackageReference Include="SJZY.InterfaceRelay.Application.Contracts" Version="7.2.5-alpha2" />
|
||||
<PackageReference Include="Volo.Abp.Http.Client" Version="7.0.2" />
|
||||
<PackageReference Include="Volo.Abp.FluentValidation" Version="7.0.2" />
|
||||
<PackageReference Include="SJZY.UserCenter.HttpApi" Version="3.1.8.17-alpha" />
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
using System.Text;
|
||||
using BSI.Stack.Rabbit;
|
||||
using SJZY.Expand.ABP.Core.PublicMethords;
|
||||
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||
using SJZY.Track.Application.Contract.Events;
|
||||
using SJZY.Track.Application.Contract.Services;
|
||||
|
||||
namespace SJZY.Track.Application.Services.Broadcasting;
|
||||
|
||||
/// <summary>
|
||||
/// 广播服务
|
||||
/// </summary>
|
||||
public class BroadcastingService : IBroadcastingService
|
||||
{
|
||||
private readonly RabbitClientBus _rabbitClientBus;
|
||||
|
||||
public BroadcastingService(RabbitClientBus rabbitClientBus)
|
||||
{
|
||||
_rabbitClientBus = rabbitClientBus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹变更广播
|
||||
/// </summary>
|
||||
/// <param name="eto"></param>
|
||||
/// <param name="subSystemCode">子系统代码</param>
|
||||
/// <param name="trackStatusCode">轨迹状态代码</param>
|
||||
/// <returns></returns>
|
||||
public void TrackChangePublicTopic(TrackUpsertEvent eto, string subSystemCode, string trackStatusCode)
|
||||
{
|
||||
var data = new TrackChangeEto
|
||||
{
|
||||
EstimatedDeliveryDate = eto.EstimatedDeliveryDate,
|
||||
TrackPlacePostcode = eto.TrackPlacePostcode,
|
||||
TrackPlaceNation = eto.TrackPlaceNation,
|
||||
TrackPlaceNationId = eto.TrackPlaceNationId,
|
||||
TrackPlaceProvince = eto.TrackPlaceProvince,
|
||||
TrackPlaceProvinceId = eto.TrackPlaceProvinceId,
|
||||
TrackPlaceCity = eto.TrackPlaceCity,
|
||||
TrackPlaceCityId = eto.TrackPlaceCityId,
|
||||
Files = eto.Files,
|
||||
Remarks = eto.Remarks,
|
||||
Source = eto.Source,
|
||||
IsVisibility = eto.IsVisibility,
|
||||
TrackTimeZone = eto.TrackTimeZone,
|
||||
TrackTime = eto.TrackTime,
|
||||
TrackPlace = eto.TrackPlace,
|
||||
TrackStatusCode = trackStatusCode,
|
||||
OrderNo = eto.OrderIdentifiers.First().OrderNo,
|
||||
EnStatus = eto.EnStatus,
|
||||
Content = eto.Content,
|
||||
TrackCode = eto.TrackCode,
|
||||
OperationMan = eto.OperationMan,
|
||||
OrderIdentifiers = eto.OrderIdentifiers,
|
||||
CustomId = eto.CustomId,
|
||||
SubSystemId = eto.SubSystemId,
|
||||
Extra = eto.Extra
|
||||
};
|
||||
|
||||
if (eto.IsAdd)
|
||||
data.Option = 1;
|
||||
else
|
||||
data.Option = 3;
|
||||
|
||||
_rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{subSystemCode}",
|
||||
Encoding.UTF8.GetBytes(data.ToJson()));
|
||||
}
|
||||
|
||||
public void TrackChangePublicTopic(TrackDeleteEvent eto, OrderIdentifier[] orderIdentifiers, string trackCode, string trackStatusCode, string subSystemCode)
|
||||
{
|
||||
var data = new TrackChangeEto
|
||||
{
|
||||
OrderIdentifiers = orderIdentifiers,
|
||||
TrackStatusCode = trackStatusCode,
|
||||
TrackCode = trackCode,
|
||||
OperationMan = eto.OperationMan,
|
||||
SubSystemId = eto.SubSystemId,
|
||||
Option = 2
|
||||
};
|
||||
|
||||
_rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{subSystemCode}",
|
||||
Encoding.UTF8.GetBytes(data.ToJson()));
|
||||
}
|
||||
|
||||
public void TrackChangePublicTopic(TrackChangeEto eto, string subSystemCode)
|
||||
{
|
||||
eto.Option = 2;
|
||||
_rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{subSystemCode}",
|
||||
Encoding.UTF8.GetBytes(eto.ToJson()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹推送完成广播
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
/// <returns></returns>
|
||||
public void TrackPushCompletedPublicTopic(TrackPushRecordDto log)
|
||||
{
|
||||
var data = new TrackPushCompletedEvent
|
||||
{
|
||||
RequestId = log.RequestId,
|
||||
IsSuccess = log.IsSuccess,
|
||||
Message = log.Message,
|
||||
OperationMan = log.OperationMan,
|
||||
PushTime = log.PushTime,
|
||||
OptionType = log.OptionType,
|
||||
IsManualPush = log.IsManualPush, //操作人不为系统用户,则认为是仍推送
|
||||
PushContent = log.PushContent,
|
||||
OrderNo = log.OrderNo,
|
||||
TrackStatus = log.TrackStatus,
|
||||
TrackContent = log.TrackContent,
|
||||
TrackTimeZone = log.TrackTimeZone,
|
||||
TrackTime = log.TrackTime,
|
||||
TrackPlace = log.TrackPlace,
|
||||
TrackCode = log.TrackCode,
|
||||
Extra = log.Extra
|
||||
};
|
||||
|
||||
_rabbitClientBus.Publish(GlobalConst.TrackPushExchange, $"TrackPush.{log.SubSystemCode}",
|
||||
Encoding.UTF8.GetBytes(data.ToJson()));
|
||||
}
|
||||
|
||||
public void TrackPushFailedPubilcTopic(TrackPushRecordDto log)
|
||||
{
|
||||
//暂时使用推送完成模型,后续可能会出现有区分度的模型
|
||||
TrackPushCompletedPublicTopic(log);
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ public partial class OrderService : ApplicationService, IOrderService
|
||||
order.OrderFlights = ObjectMapper.Map<List<OrderFlightInfo>, List<OrderFlightEntity>>(input.FlightInfos);
|
||||
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
|
||||
order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos);
|
||||
order.TemplateCodes = string.Join(',', input.TemplateCodes);
|
||||
order.TemplateCodes = input.TemplateCodes == null ? null : string.Join(',', input.TemplateCodes);
|
||||
|
||||
var orderId = await _orderRepository.CreateOrderAsync(order);
|
||||
|
||||
@ -131,7 +131,7 @@ public partial class OrderService : ApplicationService, IOrderService
|
||||
order.OrderFlights = ObjectMapper.Map<List<OrderFlightInfo>, List<OrderFlightEntity>>(input.FlightInfos);
|
||||
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
|
||||
order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos);
|
||||
order.TemplateCodes = string.Join(',', input.TemplateCodes);
|
||||
order.TemplateCodes = input.TemplateCodes == null ? null : string.Join(',', input.TemplateCodes);
|
||||
await _orderRepository.UpdateOrderAsync(order);
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
using DotNetCore.CAP;
|
||||
using SJZY.Expand.ABP.Core.Common;
|
||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||
using SJZY.Track.Application.Contract.Dtos.TrackOrder;
|
||||
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||
using SJZY.Track.Application.Contract.Events;
|
||||
using SJZY.Track.Application.Contract.Services.ProvideServices;
|
||||
using SJZY.Track.Application.Helpers;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
|
||||
using SJZY.Track.Domain.Dtos.TrackPush;
|
||||
using SJZY.Track.Domain.Queries;
|
||||
@ -26,12 +29,14 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
||||
private readonly ITrackPushConfigRepository _trackPushConfigRepository;
|
||||
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
|
||||
public TrackPushService(IOrderRepository orderRepository
|
||||
, ICapPublisher capPublisher
|
||||
, ITrackPushRecordEsRepository trackPushRecordEsRepository
|
||||
, IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService
|
||||
, ITrackPushConfigRepository trackPushConfigRepository, IProvideQueries provideQueries)
|
||||
, ITrackPushConfigRepository trackPushConfigRepository, IProvideQueries provideQueries,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository)
|
||||
{
|
||||
_orderRepository = orderRepository;
|
||||
_capPublisher = capPublisher;
|
||||
@ -39,6 +44,7 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
_requestCurrentUserService = requestCurrentUserService;
|
||||
_trackPushConfigRepository = trackPushConfigRepository;
|
||||
_provideQueries = provideQueries;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -47,7 +53,8 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("Track/Push")]
|
||||
public async Task<string> PushTrackAsync(PushTrackInput input)
|
||||
[CustomerResult]
|
||||
public async Task<UnifyResultDto> PushTrackAsync(PushTrackInput input)
|
||||
{
|
||||
input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空
|
||||
|
||||
@ -74,23 +81,92 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
|
||||
var name = userInfo.Data.UserName;
|
||||
|
||||
foreach (var group in orders.GroupBy(x => x.CustomId))
|
||||
//查出需要推送的轨迹
|
||||
var tracks = await _trackDetailsEsRepository
|
||||
.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos,
|
||||
new List<string>
|
||||
{
|
||||
input.TrackCode
|
||||
});
|
||||
if (tracks.Count == 0)
|
||||
{
|
||||
throw new BusinessException(message: "没有需要推送的轨迹");
|
||||
}
|
||||
|
||||
//存在比较字段,需要做过滤处理
|
||||
if (!string.IsNullOrWhiteSpace(input.CompareFields))
|
||||
{
|
||||
//根据输入值来进行过滤,比如选取code1,批次1的轨迹,可能会有多条,下面使用创建时间最新的一条
|
||||
tracks = tracks.Where(x =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(x.Extra))
|
||||
{
|
||||
throw new BusinessException(message: $"当前轨迹不存在扩展信息,无法利用扩展字段:{input.CompareFields}");
|
||||
}
|
||||
|
||||
var extraDict = GetExtraDictForTextJson(x.Extra);
|
||||
if (extraDict == null || !extraDict.TryGetValue(input.CompareFields, out var compareValue))
|
||||
{
|
||||
throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{input.CompareFields}");
|
||||
}
|
||||
|
||||
//补充轨迹内容
|
||||
return TextJsonHelper.EqJsonElementAndObject(compareValue, input.CompareValue);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
//不同单可能会有不同的轨迹内容,先推送只推送最新的一条
|
||||
foreach (var order in orders)
|
||||
{
|
||||
//找出每个单的某个code的最新轨迹内容
|
||||
var track = tracks.Where(x => x.OrderId == order.Id)
|
||||
.OrderByDescending(x => x.CreateTime)
|
||||
.FirstOrDefault();
|
||||
if (track == null) continue;
|
||||
|
||||
var trackPushEvent = new TrackPushEvent
|
||||
{
|
||||
OptionType = OptionType.新增,
|
||||
SubSystemId = input.SubSystemId,
|
||||
SubSystemCode = subSystemCode,
|
||||
CustomId = group.Key,
|
||||
OrderIds = group.Select(x => x.Id).ToArray(),
|
||||
CustomId = order.CustomId,
|
||||
OrderIds = new[] { order.Id },
|
||||
TrackCode = input.TrackCode,
|
||||
OperationMan = name,
|
||||
SystemPushInfo = new SystemPushStruct()
|
||||
{
|
||||
TrackStatus = track.TrackStatus,
|
||||
TrackContent = track.TrackContent,
|
||||
TrackPlace = track.TrackPlace,
|
||||
TrackTime = track.TrackTime,
|
||||
TrackTimeZone = track.TrackTimeZone,
|
||||
CompareFields = input.CompareFields,
|
||||
Extra = track.Extra
|
||||
}
|
||||
};
|
||||
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent);
|
||||
}
|
||||
|
||||
return $"即将推送轨迹代码{input.TrackCode}给{orders.Length}个订单";
|
||||
|
||||
// foreach (var group in orders.GroupBy(x => x.CustomId))
|
||||
// {
|
||||
// var trackPushEvent = new TrackPushEvent
|
||||
// {
|
||||
// OptionType = OptionType.新增,
|
||||
// SubSystemId = input.SubSystemId,
|
||||
// SubSystemCode = subSystemCode,
|
||||
// CustomId = group.Key,
|
||||
// OrderIds = group.Select(x => x.Id).ToArray(),
|
||||
// TrackCode = input.TrackCode,
|
||||
// OperationMan = name,
|
||||
// SystemPushInfo = new SystemPushStruct()
|
||||
// };
|
||||
//
|
||||
// await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent);
|
||||
// }
|
||||
|
||||
return new UnifyResultDto(true, $"即将推送轨迹代码{input.TrackCode}给{orders.Length}个订单");
|
||||
}
|
||||
|
||||
|
||||
@ -101,13 +177,14 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
/// <param name="customerId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("Track/GetTrackPushContentList")]
|
||||
public async Task<List<TrackPushContentDto>> GetTrackPushContentListAsync(int subSystemId, int customerId)
|
||||
[CustomerResult]
|
||||
public async Task<UnifyResultDto<List<TrackPushContentDto>>> GetTrackPushContentListAsync(int subSystemId, int customerId)
|
||||
{
|
||||
var list = await _trackPushConfigRepository.GetTrackPushContentListAsync(subSystemId, customerId);
|
||||
|
||||
var result = ObjectMapper.Map<List<GetTrackPushContentListVo>, List<TrackPushContentDto>>(list);
|
||||
|
||||
return result;
|
||||
return new UnifyResultDto<List<TrackPushContentDto>>(true, result, "操作成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -116,7 +193,8 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
/// <returns></returns>
|
||||
/// <param name="input"></param>
|
||||
[HttpGet("Track/GetTrackPushRecords")]
|
||||
public async Task<List<TrackPushRecordOutput>> GetTrackPushRecordsAsync([FromQuery] OrderNoInfo input)
|
||||
[CustomerResult]
|
||||
public async Task<UnifyResultDto<List<TrackPushRecordOutput>>> GetTrackPushRecordsAsync([FromQuery] OrderNoInfo input)
|
||||
{
|
||||
var orderId = await _orderRepository.GetFirstAsync(x =>
|
||||
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && input.OrderNo == x.OrderNo,
|
||||
@ -128,6 +206,14 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
||||
|
||||
var records = await _trackPushRecordEsRepository.GetTrackPushRecordsAsync(orderId);
|
||||
|
||||
return ObjectMapper.Map<List<TrackPushRecordIndex>, List<TrackPushRecordOutput>>(records);
|
||||
var res = ObjectMapper.Map<List<TrackPushRecordIndex>, List<TrackPushRecordOutput>>(records);
|
||||
return new UnifyResultDto<List<TrackPushRecordOutput>>(true, res, "操作成功");
|
||||
}
|
||||
|
||||
private Dictionary<string, object?>? GetExtraDictForTextJson(string? extraStr)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(extraStr)
|
||||
? null
|
||||
: System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(extraStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
|
||||
using SJZY.Track.Domain.Dtos.TrackTemplate;
|
||||
using SJZY.Track.Domain.Queries;
|
||||
|
||||
namespace SJZY.Track.Application.Services.ProvideServices;
|
||||
|
||||
@ -9,9 +13,12 @@ namespace SJZY.Track.Application.Services.ProvideServices;
|
||||
public partial class TrackService
|
||||
{
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
private readonly ITrackTemplateRepository _trackTemplateRepository;
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private readonly IVSystemQueries _vSystemQueries;
|
||||
|
||||
/// <summary>
|
||||
/// 查询轨迹
|
||||
/// 查询轨迹(时区补正)
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
@ -24,9 +31,12 @@ public partial class TrackService
|
||||
|
||||
var details = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos);
|
||||
|
||||
//内部子系统不过滤外部轨迹
|
||||
var isFilterExternal = await HasFilterExternalTrack();
|
||||
|
||||
// 是否对外
|
||||
var trackCodes = details.Select(x => x.TrackCode)
|
||||
.Where(x => x != GlobalConst.EmptyString)
|
||||
.WhereIf(isFilterExternal, x => x != GlobalConst.EmptyString)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
@ -51,6 +61,7 @@ public partial class TrackService
|
||||
|
||||
item.TrackDetails = trackDetails.Select(x => new TrackDetail
|
||||
{
|
||||
EsId = x.Id,
|
||||
Code = x.TrackCode,
|
||||
Status = x.TrackStatus,
|
||||
Content = x.TrackContent,
|
||||
@ -63,13 +74,13 @@ public partial class TrackService
|
||||
? null
|
||||
: input.TimeZone ?? 8,
|
||||
IsDisplay = trackContentDic.TryGetValue(x.TrackCode, out var isExternal) && isExternal,
|
||||
IsVisibility = x.IsVisibility,
|
||||
IsVisibility = x.IsVisibility,
|
||||
Source = x.Source,
|
||||
Remarks = x.Remarks,
|
||||
Files = x.Files?.Select(y => new FileItemDto
|
||||
{
|
||||
FileName = y.FileName,
|
||||
OssKey = y.OssKey
|
||||
FileName = y.FileName,
|
||||
OssKey = y.OssKey
|
||||
}).ToList(),
|
||||
TrackPlaceCity = x.TrackPlaceCity,
|
||||
TrackPlaceCityId = x.TrackPlaceCityId,
|
||||
@ -87,25 +98,308 @@ public partial class TrackService
|
||||
}
|
||||
|
||||
// 排序
|
||||
TracksOrdered(res, input);
|
||||
var sortedList = await TracksOrdered(res, input, input.SortMethod);
|
||||
|
||||
return new UnifyResultDto<List<GetTrackOutput>>(true, res, "操作成功");
|
||||
return new UnifyResultDto<List<GetTrackOutput>>(true, sortedList, "操作成功");
|
||||
}
|
||||
|
||||
private void TracksOrdered(List<GetTrackOutput> list, GetTrackInput input)
|
||||
|
||||
/// <summary>
|
||||
/// 查询轨迹(原样返回)
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("Track/QueryV2")]
|
||||
public async Task<UnifyResultDto<List<GetTrackOutput>>> QueryV2Async(GetTrackInputV2 input)
|
||||
{
|
||||
switch (input.SortMethod)
|
||||
var res = new List<GetTrackOutput>();
|
||||
input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空
|
||||
|
||||
var details = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos);
|
||||
|
||||
//内部子系统不过滤外部轨迹
|
||||
var isFilterExternal = await HasFilterExternalTrack();
|
||||
|
||||
// 是否对外
|
||||
var trackCodes = details.Select(x => x.TrackCode)
|
||||
.WhereIf(isFilterExternal, x => x != GlobalConst.EmptyString)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var trackContentDic = new Dictionary<string, bool>();
|
||||
if (!trackCodes.IsNullOrEmpty())
|
||||
{
|
||||
var trackContents = await _trackContentRepository.GetListAsync(x =>
|
||||
x.SubSystemId == input.SubSystemId && trackCodes.Contains(x.Code),
|
||||
x => new
|
||||
{
|
||||
x.Code,
|
||||
x.IsExternal
|
||||
});
|
||||
trackContents.ForEach(x => trackContentDic.Add(x.Code, x.IsExternal));
|
||||
}
|
||||
|
||||
foreach (var group in details.GroupBy(x => x.OrderId))
|
||||
{
|
||||
var item = new GetTrackOutput();
|
||||
var trackDetails = group.ToList();
|
||||
item.OrderNo = trackDetails.First().OrderNo;
|
||||
|
||||
item.TrackDetails = trackDetails.Select(x => new TrackDetail
|
||||
{
|
||||
EsId = x.Id,
|
||||
Code = x.TrackCode,
|
||||
Status = x.TrackStatus,
|
||||
Content = x.TrackContent,
|
||||
OriginContent = x.OriginTrackContent,
|
||||
Location = x.TrackPlace,
|
||||
Time = x.TrackTime,
|
||||
TimeZone = x.TrackTimeZone,
|
||||
IsDisplay = trackContentDic.TryGetValue(x.TrackCode, out var isExternal) && isExternal,
|
||||
IsVisibility = x.IsVisibility,
|
||||
Source = x.Source,
|
||||
Remarks = x.Remarks,
|
||||
Files = x.Files?.Select(y => new FileItemDto
|
||||
{
|
||||
FileName = y.FileName,
|
||||
OssKey = y.OssKey
|
||||
}).ToList(),
|
||||
TrackPlaceCity = x.TrackPlaceCity,
|
||||
TrackPlaceCityId = x.TrackPlaceCityId,
|
||||
TrackPlaceProvince = x.TrackPlaceProvince,
|
||||
TrackPlaceProvinceId = x.TrackPlaceProvinceId,
|
||||
TrackPlaceNation = x.TrackPlaceNation,
|
||||
TrackPlaceNationId = x.TrackPlaceNationId,
|
||||
TrackPlacePostcode = x.TrackPlacePostcode,
|
||||
DestinationTimeZone = x.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = x.EstimatedDeliveryDate,
|
||||
Extra = x.Extra
|
||||
}).ToList();
|
||||
|
||||
res.Add(item);
|
||||
}
|
||||
|
||||
// 排序
|
||||
var sortedList = await TracksOrdered(res, input, input.SortMethod);
|
||||
|
||||
return new UnifyResultDto<List<GetTrackOutput>>(true, sortedList, "操作成功");
|
||||
}
|
||||
|
||||
//内部系统展示所有轨迹,外部系统则要求过滤外部轨迹
|
||||
private async Task<bool> HasFilterExternalTrack()
|
||||
{
|
||||
var isFilter = true;
|
||||
if (_contextAccessor.HttpContext!.Request.Headers.TryGetValue(GlobalConst.HTTP_HEADER_SUBSYSTEMID, out var subsystemIdStr))
|
||||
{
|
||||
if (int.TryParse(subsystemIdStr, out var subsystemId))
|
||||
{
|
||||
var systemEntity = await _vSystemQueries.GetFirstAsync(x => x.Id == subsystemId);
|
||||
isFilter = systemEntity?.SystemProperty != 1;
|
||||
}
|
||||
}
|
||||
|
||||
return isFilter;
|
||||
}
|
||||
|
||||
|
||||
private async Task<List<GetTrackOutput>> TracksOrdered(List<GetTrackOutput> list, OrderNosInfo orderNosInfo, SortMethod? sortMethod)
|
||||
{
|
||||
switch (sortMethod)
|
||||
{
|
||||
case SortMethod.ByTrackTime:
|
||||
case SortMethod.ByTemplateAndTrackTime:
|
||||
// tips:quick-sort 直接修改原list
|
||||
list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time)));
|
||||
break;
|
||||
case null:
|
||||
case SortMethod.ByTrackTimeDesc:
|
||||
case SortMethod.ByTemplateAndTrackTimeDesc:
|
||||
list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time)));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式");
|
||||
throw new ArgumentOutOfRangeException(nameof(sortMethod), sortMethod, "不支持的排序方式");
|
||||
}
|
||||
|
||||
if (sortMethod != SortMethod.ByTemplateAndTrackTime
|
||||
&& sortMethod != SortMethod.ByTemplateAndTrackTimeDesc)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
//查出订单模板
|
||||
var templates = await _trackTemplateRepository.GetTrackTemplateListAsync(new GetTrackTemplateListInputVo
|
||||
{
|
||||
SubSystemId = orderNosInfo.SubSystemId
|
||||
});
|
||||
|
||||
if (templates.Count == 0)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
//查出订单和模板的关系,构建订单号和模板code的关系
|
||||
var orderNoTemplateDict = (await _orderRepository
|
||||
.GetOrderTemplateAsync(orderNosInfo.SubSystemId, orderNosInfo.OrderType, orderNosInfo.OrderNos))
|
||||
.ToDictionary(x => x.OrderNo, x => x.TemplateCodes?.Split(",").ToHashSet());
|
||||
|
||||
//查询出订单和模板的关联关系,保证该订单使用自己的模板排序
|
||||
foreach (var getTrackOutput in list)
|
||||
{
|
||||
//查看该订单具有的模板
|
||||
var curOrderNoTemplateCodes = orderNoTemplateDict[getTrackOutput.OrderNo];
|
||||
if (curOrderNoTemplateCodes == null || curOrderNoTemplateCodes.Count == 0) continue;
|
||||
|
||||
//选出这个订单号所具有的模板
|
||||
var tipTemplates = templates.Where(x => curOrderNoTemplateCodes.Contains(x.TemplateCode)).ToList();
|
||||
if (tipTemplates.Count == 0) continue;
|
||||
|
||||
getTrackOutput.TrackDetails = SortByTemplatesAsync(getTrackOutput.TrackDetails, tipTemplates, sortMethod == SortMethod.ByTemplateAndTrackTime);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹发生时间(统一utc)排序,相同时间按模板排序,考虑多个模板的情况
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static List<TrackDetail> SortByTemplatesAsync(List<TrackDetail> seq, List<TrackTemplateOutputVo> templates, bool isAsc = true)
|
||||
{
|
||||
//转化为统一时间
|
||||
var trackWraps = seq.Select(x => new TrackWrap(x));
|
||||
var sortedTracks = (isAsc
|
||||
? trackWraps.OrderBy(x => x.Time)
|
||||
: trackWraps.OrderByDescending(x => x.Time)).ToList();
|
||||
|
||||
|
||||
//用于统计时间相同的轨迹
|
||||
var timeEqTrackDict = new Dictionary<DateTime, List<TrackIdxWarp>>();
|
||||
for (var i = 0; i < sortedTracks.Count; i++)
|
||||
{
|
||||
var trackWrap = sortedTracks[i];
|
||||
if (timeEqTrackDict.TryGetValue(trackWrap.Time, out var list))
|
||||
list.Add(new TrackIdxWarp(trackWrap.Track, i));
|
||||
else
|
||||
timeEqTrackDict.Add(trackWrap.Time, new List<TrackIdxWarp>
|
||||
{
|
||||
new TrackIdxWarp(trackWrap.Track, i)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//选出需要按模板重排序的轨迹
|
||||
var timeEqTracks = timeEqTrackDict
|
||||
.Where(kv => kv.Value.Count > 1)
|
||||
.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
|
||||
//初始化为最后一个模板排序
|
||||
var preSortDict = templates[templates.Count - 1]
|
||||
.TemplateContents
|
||||
.OrderBy(x => x.Sort)
|
||||
.ToDictionary(x => x.Code, x => x.Sort);
|
||||
|
||||
for (var i = templates.Count - 2; i >= 0; i--)
|
||||
{
|
||||
var curCodeSortDict = templates[i]
|
||||
.TemplateContents
|
||||
.ToDictionary(x => x.Code, y => y.Sort);
|
||||
|
||||
//没在之前模板出现的code
|
||||
var noTipPreCodeSortDict = curCodeSortDict
|
||||
.Where(x => !preSortDict.ContainsKey(x.Key))
|
||||
.ToDictionary(x => x.Key, y => y.Value);
|
||||
|
||||
//插入未命中的模板code
|
||||
foreach (var (noTipCode, curNoTipCodeSort) in noTipPreCodeSortDict)
|
||||
{
|
||||
//初始化插入位置
|
||||
var insertPos = -1;
|
||||
foreach (var (preCode, _) in preSortDict)
|
||||
{
|
||||
if (curCodeSortDict.TryGetValue(preCode, out var preCodeSort))
|
||||
{
|
||||
//未命中的相对于之前模板的偏后,设置插入位置在
|
||||
if (preCodeSort < curNoTipCodeSort)
|
||||
{
|
||||
insertPos = preSortDict[preCode] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//结束了还没选好位置,未命中的code相对于之前的模板code在当前模板最前面
|
||||
if (insertPos == -1)
|
||||
{
|
||||
foreach (var (c, s) in preSortDict)
|
||||
preSortDict[c] = s + 1;
|
||||
preSortDict[noTipCode] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var (c, s) in preSortDict.Where(x => x.Value >= insertPos))
|
||||
preSortDict[c] = s + 1;
|
||||
preSortDict[noTipCode] = insertPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var trackIdxWarps in timeEqTracks.Values)
|
||||
{
|
||||
var curIndex = trackIdxWarps.Min(x => x.Index);
|
||||
//按模板从小到大排序
|
||||
var sortByTemplate = (isAsc
|
||||
? trackIdxWarps
|
||||
.OrderBy(x => preSortDict.GetValueOrDefault(x.Track.Code, int.MaxValue))
|
||||
: trackIdxWarps
|
||||
.OrderByDescending(x => preSortDict.GetValueOrDefault(x.Track.Code, int.MaxValue))
|
||||
).ToList();
|
||||
for (var j = 0; j < sortByTemplate.Count; j++)
|
||||
{
|
||||
var track = sortByTemplate[j];
|
||||
//当前索引不对应
|
||||
if (track.Index != curIndex + j)
|
||||
{
|
||||
var temp1 = sortedTracks[track.Index].Track;
|
||||
var temp2 = sortedTracks[curIndex + j].Track;
|
||||
sortedTracks[track.Index].Track = temp2;
|
||||
sortedTracks[curIndex + j].Track = temp1;
|
||||
trackIdxWarps.First(x => x.Index == curIndex + j).Index = track.Index;
|
||||
track.Index = curIndex + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sortedTracks.Select(x => x.Track).ToList();
|
||||
}
|
||||
|
||||
|
||||
private class TrackIdxWarp
|
||||
{
|
||||
public TrackDetail Track { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
public TrackIdxWarp(TrackDetail track, int index)
|
||||
{
|
||||
Track = track;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class TrackWrap
|
||||
{
|
||||
public TrackDetail Track { get; set; }
|
||||
|
||||
public DateTime Time { get; set; }
|
||||
|
||||
public TrackWrap(TrackDetail track)
|
||||
{
|
||||
Track = track;
|
||||
var timeZone = track.TimeZone ?? GlobalConst.NoneTrackTimeZone;
|
||||
Time = Math.Abs(timeZone - GlobalConst.NoneTrackTimeZone) < 1
|
||||
? track.Time
|
||||
: track.Time.Subtract(TimeSpan.FromHours(timeZone));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
using DotNetCore.CAP;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||
using SJZY.Track.Application.Contract.Events;
|
||||
using SJZY.Track.Application.Contract.Services.ProvideServices;
|
||||
using SJZY.Track.Application.Helpers;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
|
||||
using SJZY.Track.Domain.Enums;
|
||||
using SJZY.Track.Domain.Queries;
|
||||
using SJZY.UserCenter.HttpApi.Services;
|
||||
using SJZY.UserCenter.HttpApi.Services.User;
|
||||
using Volo.Abp.Http.Client.DynamicProxying;
|
||||
@ -24,149 +28,25 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
||||
private readonly ITrackContentRepository _trackContentRepository;
|
||||
|
||||
public TrackService(IOrderRepository orderRepository, ICapPublisher capPublisher,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository,
|
||||
IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService)
|
||||
public TrackService(IOrderRepository orderRepository,
|
||||
ICapPublisher capPublisher,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||
ITrackContentRepository trackContentRepository,
|
||||
IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService,
|
||||
ITrackTemplateRepository trackTemplateRepository,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IVSystemQueries vSystemQueries)
|
||||
{
|
||||
_orderRepository = orderRepository;
|
||||
_capPublisher = capPublisher;
|
||||
_trackContentRepository = trackContentRepository;
|
||||
_requestCurrentUserService = requestCurrentUserService;
|
||||
_vSystemQueries = vSystemQueries;
|
||||
_contextAccessor = contextAccessor;
|
||||
_trackTemplateRepository = trackTemplateRepository;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增、更新轨迹(存在就更新)
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessException"></exception>
|
||||
[HttpPost("Track/Upsert")]
|
||||
public async Task<UnifyResultDto> UpsertTrackAsync(UpsertTrackInput input)
|
||||
{
|
||||
var order = await _orderRepository.GetFirstAsync(x =>
|
||||
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo,
|
||||
x => new
|
||||
{
|
||||
x.Id,
|
||||
x.CustomId
|
||||
});
|
||||
if (order == default)
|
||||
{
|
||||
throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
|
||||
}
|
||||
|
||||
if (!GlobalConst.SupportTrackSources.Contains(input.Source))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹来源是必须的");
|
||||
}
|
||||
|
||||
//要求时间在当前时间的前后100年之间内
|
||||
bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100));
|
||||
if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime) || ValidateTrackTime(input.EstimatedDeliveryDate))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹时间不合法");
|
||||
}
|
||||
|
||||
if ((input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue) ||
|
||||
(input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false))
|
||||
{
|
||||
throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入");
|
||||
}
|
||||
|
||||
//当修改时,如果为来源为外部提供商则不允许修改
|
||||
if (!input.IsAdd && input.Source == (int) TrackSourceEnum.ExternalServiceProvide)
|
||||
{
|
||||
throw new BusinessException(message: "来源为外部服务商轨迹不允许修改");
|
||||
}
|
||||
|
||||
var trackContent = await _trackContentRepository.GetByCodeAsync(input.SubSystemId, input.TrackCode);
|
||||
if (trackContent == default)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{input.TrackCode}轨迹内容不存在");
|
||||
}
|
||||
|
||||
//指示是否为手动操作
|
||||
var manualOperation = input.Source == (int) TrackSourceEnum.Artificial;
|
||||
|
||||
//不允许手动创建
|
||||
if (manualOperation && input.IsAdd && !trackContent.IsAllowManuallyCreate)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动创建");
|
||||
}
|
||||
|
||||
//不允许手动更新
|
||||
if (manualOperation && !input.IsAdd && !trackContent.IsAllowManuallyUpdate)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动更新");
|
||||
}
|
||||
|
||||
var tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true))
|
||||
.Where(x => x.TrackTime == input.TrackTime)
|
||||
.ToList();
|
||||
|
||||
//当为更新操作时发现更新的数目为0进行重试操作
|
||||
if (!input.IsAdd && tracks.Count == 0)
|
||||
{
|
||||
var curRetryCount = 0;
|
||||
var success = false;
|
||||
while (!success && curRetryCount < GlobalConst.MaxUpdateTrackRetryCount)
|
||||
{
|
||||
try
|
||||
{
|
||||
tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true))
|
||||
.Where(x => x.TrackTime == input.TrackTime)
|
||||
.ToList();
|
||||
if (tracks.Count > 0)
|
||||
success = true;
|
||||
await Task.Delay(300);
|
||||
}
|
||||
finally
|
||||
{
|
||||
curRetryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tracks.Count == 0)
|
||||
{
|
||||
throw new BusinessException(message: $"订单:{input.OrderNo},轨迹代码:{input.TrackCode}没有要更新的记录");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改
|
||||
if (!input.IsAdd && tracks.Count > 1)
|
||||
{
|
||||
throw new BusinessException(message: $"订单:{input.OrderNo},轨迹代码:{input.TrackCode}存在多条记录,不允许修改");
|
||||
}
|
||||
|
||||
var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(input.OptionUserId);
|
||||
if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null)
|
||||
{
|
||||
//TODO: log || ex
|
||||
throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}");
|
||||
}
|
||||
|
||||
var name = userInfo.Data.UserName;
|
||||
|
||||
// 新增/更新轨迹
|
||||
var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(input);
|
||||
@event.SubSystemId = input.SubSystemId;
|
||||
@event.CustomId = order.CustomId;
|
||||
@event.OrderIdentifiers = new[]
|
||||
{
|
||||
new OrderIdentifier
|
||||
{
|
||||
OrderId = order.Id,
|
||||
OrderNo = input.OrderNo,
|
||||
OrderType = input.OrderType,
|
||||
}
|
||||
};
|
||||
@event.OperationMan = name;
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
|
||||
return new UnifyResultDto(true, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除轨迹
|
||||
/// </summary>
|
||||
@ -193,29 +73,69 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
|
||||
var name = userInfo.Data.UserName;
|
||||
|
||||
//删除轨迹约束,只要其中有一条来源是外部的就立即返回错误
|
||||
var tracks = await _trackDetailsEsRepository
|
||||
.GetListAsync(new[] { orderId },
|
||||
input.TrackIdentifiers.Select(x => x.TrackCode).ToList(),
|
||||
TrackSourceEnum.ExternalServiceProvide);
|
||||
var tracks = new List<TrackDetailsIndex>();
|
||||
var existsExternal = false;
|
||||
var esIds = input.EsIds?.Distinct().ToArray();
|
||||
//优先使用esId
|
||||
if (esIds != null && esIds.Length > 0)
|
||||
{
|
||||
tracks = await _trackDetailsEsRepository.GetDataByIds(esIds);
|
||||
existsExternal = tracks.Any(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide);
|
||||
}
|
||||
else
|
||||
{
|
||||
var trackCodes = input.TrackIdentifiers?.Select(x => x.TrackCode).ToList();
|
||||
var trackIds = input.TrackIdentifiers?.Select(y => $"{y.TrackCode}{y.TrackTime}").ToHashSet();
|
||||
//没有任何需要操作的轨迹
|
||||
if (trackIds == null || trackIds.Count == 0)
|
||||
{
|
||||
throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数");
|
||||
}
|
||||
|
||||
//当要删除的轨迹标识出现交叉则不允许删除
|
||||
var intersect = tracks.Select(x => $"{x.TrackCode}{x.TrackTime}")
|
||||
.Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList();
|
||||
if (intersect.Count > 0)
|
||||
//删除轨迹约束,只要其中有一条来源是外部的就立即返回错误
|
||||
tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCodes);
|
||||
//检查删除的轨迹中是否包含外部轨迹
|
||||
existsExternal = tracks
|
||||
.Where(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide)
|
||||
.WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(y.Extra))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹");
|
||||
}
|
||||
|
||||
var extraDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(y.Extra);
|
||||
if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement))
|
||||
return TextJsonHelper.EqJsonElementAndObject(compareValueJsonElement, input.CompareValue);
|
||||
|
||||
return false;
|
||||
})
|
||||
.Select(x => $"{x.TrackCode}{x.TrackTime}")
|
||||
.Any(x => trackIds.Contains(x));
|
||||
}
|
||||
|
||||
if (existsExternal)
|
||||
{
|
||||
throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除");
|
||||
}
|
||||
|
||||
// 删除轨迹
|
||||
var @event = new TrackDeleteEvent
|
||||
if (tracks.Count == 0)
|
||||
{
|
||||
OrderIds = new[] { orderId },
|
||||
TrackIdentifiers = input.TrackIdentifiers,
|
||||
SubSystemId = input.SubSystemId,
|
||||
OperationMan = name
|
||||
};
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event);
|
||||
throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数");
|
||||
}
|
||||
|
||||
// 删除轨迹
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe,
|
||||
new TrackDeleteEvent
|
||||
{
|
||||
EsIds = input.EsIds?.ToArray(),
|
||||
OrderIds = new[] { orderId },
|
||||
CompareFields = input.CompareFields,
|
||||
CompareValue = input.CompareValue,
|
||||
TrackIdentifiers = input.TrackIdentifiers,
|
||||
SubSystemId = input.SubSystemId,
|
||||
OperationMan = name
|
||||
});
|
||||
|
||||
return new UnifyResultDto(true, true);
|
||||
}
|
||||
@ -297,7 +217,21 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
TrackSourceEnum.ExternalServiceProvide);
|
||||
|
||||
//当要删除的轨迹标识出现交叉则不允许删除
|
||||
var intersect = tracks.Select(x => $"{x.TrackCode}{x.TrackTime}")
|
||||
var intersect = tracks
|
||||
.WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(y.Extra))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹");
|
||||
}
|
||||
|
||||
var extraDict = TextJsonHelper.DeserializeToDictionary(y.Extra);
|
||||
if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement))
|
||||
return TextJsonHelper.EqJsonElementAndObject(compareValueJsonElement, input.CompareValue);
|
||||
|
||||
return false;
|
||||
})
|
||||
.Select(x => $"{x.TrackCode}{x.TrackTime}")
|
||||
.Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList();
|
||||
if (intersect.Count > 0)
|
||||
{
|
||||
@ -309,6 +243,8 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
{
|
||||
OrderIds = orderIds.ToArray(),
|
||||
TrackIdentifiers = input.TrackIdentifiers,
|
||||
CompareFields = input.CompareFields,
|
||||
CompareValue = input.CompareValue,
|
||||
SubSystemId = input.SubSystemId,
|
||||
OperationMan = userInfo.Data.UserName,
|
||||
};
|
||||
@ -317,6 +253,76 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
return new UnifyResultDto(true, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增、更新轨迹(存在就更新)
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessException"></exception>
|
||||
[HttpPost("Track/Upsert")]
|
||||
public async Task<UnifyResultDto> UpsertTrackAsync(UpsertTrackInput input)
|
||||
{
|
||||
var order = await _orderRepository.GetFirstAsync(x =>
|
||||
x.SubSystemId == input.SubSystemId
|
||||
&& x.OrderType == input.OrderType
|
||||
&& x.OrderNo == input.OrderNo,
|
||||
x => new
|
||||
{
|
||||
x.Id,
|
||||
x.OrderNo,
|
||||
x.CustomId
|
||||
});
|
||||
if (order == default)
|
||||
{
|
||||
throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
|
||||
}
|
||||
|
||||
// 输入参数的静态规则检查
|
||||
// 轨迹内容上的约束检查
|
||||
// 更新轨迹时是否可以匹配到轨迹的检查
|
||||
await TrackUpsertValidation(input.IsAdd,
|
||||
input.SubSystemId,
|
||||
order.Id,
|
||||
order.OrderNo,
|
||||
input.TrackCode,
|
||||
input.Source,
|
||||
input.TrackTime,
|
||||
input.NewTrackTime,
|
||||
input.EstimatedDeliveryDate,
|
||||
input.DestinationTimeZone,
|
||||
input.Extra,
|
||||
input.CompareFields);
|
||||
|
||||
var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync();
|
||||
if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null)
|
||||
{
|
||||
//todo:保留之前的方式(FBA在用) 后续可能去除
|
||||
userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(input.OptionUserId);
|
||||
|
||||
if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null)
|
||||
throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}");
|
||||
}
|
||||
|
||||
var name = userInfo.Data.UserName;
|
||||
|
||||
// 新增/更新轨迹
|
||||
var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(input);
|
||||
@event.SubSystemId = input.SubSystemId;
|
||||
@event.CustomId = order.CustomId;
|
||||
@event.OrderIdentifiers = new[]
|
||||
{
|
||||
new OrderIdentifier
|
||||
{
|
||||
OrderId = order.Id,
|
||||
OrderNo = input.OrderNo,
|
||||
OrderType = input.OrderType,
|
||||
}
|
||||
};
|
||||
@event.OperationMan = name;
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
|
||||
return new UnifyResultDto(true, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量新增、更新轨迹
|
||||
/// </summary>
|
||||
@ -328,8 +334,9 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
{
|
||||
input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空
|
||||
var orders = await _orderRepository.GetListAsync(x =>
|
||||
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType &&
|
||||
input.OrderNos.Contains(x.OrderNo),
|
||||
x.SubSystemId == input.SubSystemId
|
||||
&& x.OrderType == input.OrderType
|
||||
&& input.OrderNos.Contains(x.OrderNo),
|
||||
x => new
|
||||
{
|
||||
x.Id,
|
||||
@ -342,93 +349,26 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
throw new BusinessException(message: "订单一个都不存在");
|
||||
}
|
||||
|
||||
if (!GlobalConst.SupportTrackSources.Contains(input.Source))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹来源是必须的");
|
||||
}
|
||||
|
||||
//当修改时,如果为来源为外部提供商则不允许修改
|
||||
if (!input.IsAdd && input.Source == (int) TrackSourceEnum.ExternalServiceProvide)
|
||||
{
|
||||
throw new BusinessException(message: "来源为外部服务商轨迹不允许修改");
|
||||
}
|
||||
|
||||
// 校验主体:批量新增只选取第一条订单进行校验
|
||||
//【新增】存在指定轨迹的内容,进行更新覆盖(只处理一条的情况,并且决定权交给用户),不存在直接插入即可
|
||||
//【更新】存在指定轨迹的内容(匹配到多条则不处理)
|
||||
var order = orders.First();
|
||||
|
||||
//要求时间在当前时间的前后100年之间内
|
||||
bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100));
|
||||
if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime) || ValidateTrackTime(input.EstimatedDeliveryDate))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹时间不合法");
|
||||
}
|
||||
|
||||
if ((input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue) ||
|
||||
(input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false))
|
||||
{
|
||||
throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入");
|
||||
}
|
||||
|
||||
var trackContent = await _trackContentRepository.GetByCodeAsync(input.SubSystemId, input.TrackCode);
|
||||
if (trackContent == default)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{input.TrackCode}轨迹内容不存在");
|
||||
}
|
||||
|
||||
//指示是否为手动操作
|
||||
var manualOperation = input.Source == (int) TrackSourceEnum.Artificial;
|
||||
|
||||
//不允许手动创建
|
||||
if (manualOperation && input.IsAdd && !trackContent.IsAllowManuallyCreate)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动创建");
|
||||
}
|
||||
|
||||
//不允许手动更新
|
||||
if (manualOperation && !input.IsAdd && !trackContent.IsAllowManuallyUpdate)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动更新");
|
||||
}
|
||||
|
||||
var tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true))
|
||||
.Where(x => x.TrackTime == input.TrackTime)
|
||||
.ToList();
|
||||
|
||||
//当为更新操作时发现更新的数目为0进行重试操作
|
||||
if (!input.IsAdd && tracks.Count == 0)
|
||||
{
|
||||
var curRetryCount = 0;
|
||||
var success = false;
|
||||
while (!success && curRetryCount < GlobalConst.MaxUpdateTrackRetryCount)
|
||||
{
|
||||
try
|
||||
{
|
||||
tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true))
|
||||
.Where(x => x.TrackTime == input.TrackTime)
|
||||
.ToList();
|
||||
if (tracks.Count > 0)
|
||||
success = true;
|
||||
await Task.Delay(300);
|
||||
}
|
||||
finally
|
||||
{
|
||||
curRetryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tracks.Count == 0)
|
||||
{
|
||||
throw new BusinessException(message: $"订单:[{string.Join(",", input.OrderNos)}],轨迹代码:{input.TrackCode}没有要更新的记录");
|
||||
}
|
||||
}
|
||||
|
||||
//更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改
|
||||
if (!input.IsAdd && tracks.Count > 1)
|
||||
{
|
||||
throw new BusinessException(message: $"订单:{order.OrderNo},轨迹代码:{input.TrackCode}存在多条记录,不允许修改");
|
||||
}
|
||||
// 输入参数的静态规则检查
|
||||
// 轨迹内容上的约束检查
|
||||
// 更新轨迹时是否可以匹配到轨迹的检查
|
||||
await TrackUpsertValidation(input.IsAdd,
|
||||
input.SubSystemId,
|
||||
order.Id,
|
||||
order.OrderNo,
|
||||
input.TrackCode,
|
||||
input.Source,
|
||||
input.TrackTime,
|
||||
input.NewTrackTime,
|
||||
input.EstimatedDeliveryDate,
|
||||
input.DestinationTimeZone,
|
||||
input.Extra,
|
||||
input.CompareFields);
|
||||
|
||||
// 获取用户name
|
||||
var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync();
|
||||
@ -473,11 +413,168 @@ public partial class TrackService : ApplicationService, ITrackService
|
||||
TrackPlacePostcode = input.TrackPlacePostcode,
|
||||
EstimatedDeliveryDate = input.EstimatedDeliveryDate,
|
||||
DestinationTimeZone = input.DestinationTimeZone,
|
||||
Extra = input.Extra
|
||||
CompareFields = input.CompareFields,
|
||||
Extra = input.Extra,
|
||||
ForcedPush = input.ForcedPush,
|
||||
IsToMq = input.IsToMq,
|
||||
};
|
||||
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
|
||||
}
|
||||
|
||||
return new UnifyResultDto(true, true);
|
||||
}
|
||||
|
||||
//在轨迹更新主流程之前的前置检查
|
||||
private async Task TrackUpsertValidation(
|
||||
bool isAdd,
|
||||
int subSystemId,
|
||||
int orderId,
|
||||
string orderNo,
|
||||
string trackCode,
|
||||
int source,
|
||||
DateTime trackTime,
|
||||
DateTime? newTrackTime,
|
||||
DateTime? estimatedDeliveryDate,
|
||||
float? destinationTimeZone,
|
||||
string? extra,
|
||||
string? compareFields
|
||||
)
|
||||
{
|
||||
#region 静态规则检查
|
||||
|
||||
// 约束轨迹来源只能选取 1-外部 2-内部 3-手动
|
||||
if (!GlobalConst.SupportTrackSources.Contains(source))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹来源是必须的,1:外部服务商 2:内部系统 3:人工操作");
|
||||
}
|
||||
|
||||
//当修改时,如果为来源为外部提供商则不允许修改
|
||||
if (!isAdd && source == (int) TrackSourceEnum.ExternalServiceProvide)
|
||||
{
|
||||
throw new BusinessException(message: "来源为外部服务商轨迹不允许修改");
|
||||
}
|
||||
|
||||
//要求时间在当前时间的前后100年之间内
|
||||
bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100));
|
||||
if (ValidateTrackTime(trackTime) || ValidateTrackTime(newTrackTime) || ValidateTrackTime(estimatedDeliveryDate))
|
||||
{
|
||||
throw new BusinessException(message: "轨迹时间不合法");
|
||||
}
|
||||
|
||||
if ((estimatedDeliveryDate.HasValue == false && destinationTimeZone.HasValue) ||
|
||||
(estimatedDeliveryDate.HasValue && destinationTimeZone.HasValue == false))
|
||||
{
|
||||
throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(compareFields) && string.IsNullOrWhiteSpace(extra))
|
||||
{
|
||||
throw new BusinessException(message: "当输入了【轨迹对比字段】则轨迹扩展是必须的的");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 轨迹内容中的配置规则检查
|
||||
|
||||
var trackContent = await _trackContentRepository.GetByCodeAsync(subSystemId, trackCode);
|
||||
if (trackContent == default)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{trackCode}轨迹内容不存在");
|
||||
}
|
||||
|
||||
//指示是否为手动操作
|
||||
var manualOperation = source == (int) TrackSourceEnum.Artificial;
|
||||
|
||||
//不允许手动创建
|
||||
if (manualOperation && isAdd && !trackContent.IsAllowManuallyCreate)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{trackCode}不允许手动创建");
|
||||
}
|
||||
|
||||
//不允许手动更新
|
||||
if (manualOperation && !isAdd && !trackContent.IsAllowManuallyUpdate)
|
||||
{
|
||||
throw new BusinessException(message: $"轨迹代码:{trackCode}不允许手动更新");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
//轨迹新增,不允许重复的轨迹提前拦截
|
||||
if (isAdd)
|
||||
{
|
||||
//允许重复,跳过检查
|
||||
if (trackContent.IsRepeatable) return;
|
||||
//找到这个订单的这个轨迹code的所有轨迹
|
||||
var tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields);
|
||||
if (tracks.Count > 0)
|
||||
throw new BusinessException(message: $"订单:[{orderNo}],轨迹代码:{trackCode}不允许重复创建轨迹");
|
||||
}
|
||||
//针对于轨迹更新检查
|
||||
else
|
||||
{
|
||||
//找到这个订单的这个轨迹code的所有轨迹,
|
||||
var tracks = await RetryQueryTrackAsync(orderId, trackCode, trackTime, extra, compareFields);
|
||||
//不存在需要更新的轨迹
|
||||
if (tracks.Count == 0)
|
||||
throw new BusinessException(message: $"订单:[{orderNo}],轨迹代码:{trackCode}没有要更新的记录");
|
||||
|
||||
//更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改
|
||||
if (tracks.Count > 1)
|
||||
throw new BusinessException(message: $"订单:{orderNo},轨迹代码:{trackCode}存在多条记录,不允许修改");
|
||||
}
|
||||
}
|
||||
|
||||
// 重试查询轨迹,直到存在符合要求的轨迹,或者超过最大重试次数
|
||||
private async Task<List<TrackDetailsIndex>> RetryQueryTrackAsync(int orderId, string trackCode, DateTime trackTime, string? extra, string? compareFields)
|
||||
{
|
||||
var tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields);
|
||||
if (tracks.Count > 0)
|
||||
return tracks;
|
||||
|
||||
//重试阶段
|
||||
var curRetryCount = 0;
|
||||
while (curRetryCount < GlobalConst.MaxUpdateTrackRetryCount) //tips:后续将最大重试次数提出到配置中
|
||||
{
|
||||
try
|
||||
{
|
||||
tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields);
|
||||
if (tracks.Count > 0)
|
||||
return tracks;
|
||||
//指数退避等待
|
||||
var delay = TimeSpan.FromMilliseconds(Math.Pow(2, curRetryCount) * 150); // 150ms, 300ms, 600ms, ...
|
||||
await Task.Delay(delay);
|
||||
}
|
||||
finally
|
||||
{
|
||||
curRetryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//超过最大重试次数还没找到
|
||||
return tracks;
|
||||
}
|
||||
|
||||
//查询并按比较字段过滤轨迹,当比较字段为空时则使用轨迹发生时间过滤
|
||||
//tips:后续进行投影缩参优化
|
||||
private async Task<List<TrackDetailsIndex>> QueryAndFilterAsync(int orderId1, string trackCode1, DateTime trackTime1, string? extra1, string? compareFields1)
|
||||
{
|
||||
var tracks1 = await _trackDetailsEsRepository.GetListAsync(new[] { orderId1 }, trackCode1, true);
|
||||
//无比较字段时使用轨迹时间参与过滤(兼容老版本)
|
||||
if (string.IsNullOrWhiteSpace(compareFields1))
|
||||
{
|
||||
return tracks1.Where(x => x.TrackTime == trackTime1).ToList();
|
||||
}
|
||||
|
||||
return tracks1.Where(x =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(x.Extra))
|
||||
throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹");
|
||||
|
||||
var extraJsonElement = TextJsonHelper.DeserializeToJsonElement(x.Extra);
|
||||
var inputExtraJsonElement = TextJsonHelper.DeserializeToJsonElement(extra1);
|
||||
|
||||
return TextJsonHelper.EqByJsonElementField(extraJsonElement, inputExtraJsonElement, compareFields1);
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ using SJZY.Expand.ABP.Core.PublicMethords;
|
||||
using SJZY.Expand.AliyunOSS;
|
||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||
using SJZY.Track.Application.Contract.Dtos.TrackContents;
|
||||
using SJZY.Track.Application.Contract.Services;
|
||||
using SJZY.Track.Application.Localization;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
||||
@ -13,7 +14,7 @@ using SJZY.Track.Domain.Aggregates.TrackFlagAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
|
||||
using SJZY.Track.Domain.Dtos.TrackContents;
|
||||
using SJZY.Track.Domain.Dtos.TrackTemplate;
|
||||
using SJZY.Track.Domain.Enums;
|
||||
using SJZY.Track.Domain.Queries;
|
||||
|
||||
namespace SJZY.Track.Application.Services.TrackContents;
|
||||
@ -32,6 +33,7 @@ public class TrackContentService : ApplicationService
|
||||
private readonly IBasicQuery<TrackStatusEntity> _trackStatusBasicQuery;
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||
private readonly ITrackPushCacheService _trackPushCacheService;
|
||||
|
||||
public TrackContentService(
|
||||
IStringLocalizer<TrackLocalizationResource> stringLocalizer,
|
||||
@ -40,7 +42,7 @@ public class TrackContentService : ApplicationService
|
||||
IBasicQuery<TrackFlagEntity> trackFlagBasicQuery,
|
||||
IOrderRepository orderRepository,
|
||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||
ITrackTemplateRepository trackTemplateRepository)
|
||||
ITrackTemplateRepository trackTemplateRepository, ITrackPushCacheService trackPushCacheService)
|
||||
{
|
||||
_stringLocalizer = stringLocalizer;
|
||||
_trackContentRepository = trackContentRepository;
|
||||
@ -49,6 +51,7 @@ public class TrackContentService : ApplicationService
|
||||
_orderRepository = orderRepository;
|
||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||
_trackTemplateRepository = trackTemplateRepository;
|
||||
_trackPushCacheService = trackPushCacheService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -289,9 +292,40 @@ public class TrackContentService : ApplicationService
|
||||
if (order == default)
|
||||
throw new BusinessException(message: "订单不存在!");
|
||||
|
||||
var res = new UnifyResultDto<List<GetAvailableContentOutput>>(true)
|
||||
{
|
||||
Data = new List<GetAvailableContentOutput>()
|
||||
};
|
||||
|
||||
//获取轨迹详情
|
||||
var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id);
|
||||
|
||||
// 删除时去除掉外部服务商轨迹
|
||||
if (input.TrackOptionType == TrackOptionType.删除)
|
||||
{
|
||||
trackDetails = trackDetails.Where(m => m.Source != (int) TrackSourceEnum.ExternalServiceProvide).ToList();
|
||||
}
|
||||
//进行推送时,匹配订单类型一致的轨迹
|
||||
if (input.TrackOptionType == TrackOptionType.推送)
|
||||
{
|
||||
var pushConfigs = await _trackPushCacheService.GetPushContentConfigsAsync(order.SubSystemId, order.CustomId);
|
||||
//没有推送配置也不会展示任何下拉
|
||||
if (pushConfigs == null || pushConfigs.Count == 0) return res;
|
||||
//选订单类型和配置订单类型一致的配置的轨迹代码
|
||||
var trackCodes = pushConfigs.Where(m => m.OrderType == order.OrderType)
|
||||
.Select(x=>x.TrackCode)
|
||||
.Distinct()
|
||||
.ToHashSet();
|
||||
//根据配置过滤轨迹
|
||||
trackDetails = trackDetails.Where(m => trackCodes.Contains(m.TrackCode)).ToList();
|
||||
}
|
||||
|
||||
//进行删除和推送行为无任何轨迹内容,直接返回为空即可
|
||||
if (input.TrackOptionType is TrackOptionType.删除 or TrackOptionType.推送 && trackDetails.Count == 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
//获取当前子系统下所有的轨迹内容
|
||||
var contentList = await _trackContentRepository.GetListBySystemIdAsync(input.SystemId);
|
||||
if (contentList == null)
|
||||
@ -305,11 +339,6 @@ public class TrackContentService : ApplicationService
|
||||
contentList = contentList.Where(m => template.Contains(m.Code)).ToList();
|
||||
}
|
||||
|
||||
var res = new UnifyResultDto<List<GetAvailableContentOutput>>(true)
|
||||
{
|
||||
Data = new List<GetAvailableContentOutput>()
|
||||
};
|
||||
|
||||
foreach (var item in contentList)
|
||||
{
|
||||
//新增时跳过已存在轨迹内容
|
||||
@ -344,7 +373,7 @@ public class TrackContentService : ApplicationService
|
||||
}
|
||||
|
||||
|
||||
//修改操作,查轨迹内容列表反映明细表数据,重新构造响应数据
|
||||
//修改/删除/推送 操作,查轨迹内容列表反映明细表数据,重新构造响应数据
|
||||
var matchContent = new List<GetAvailableContentOutput>();
|
||||
var contents = res.Data.Select(x => new
|
||||
{
|
||||
|
||||
@ -51,6 +51,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
|
||||
x.Id,
|
||||
x.IsAutoPush,
|
||||
x.IsAllPush,
|
||||
x.IsAllPushWithLatest,
|
||||
x.IsCanDelete,
|
||||
x.IsCanUpdate,
|
||||
x.SubSystemId,
|
||||
@ -76,6 +77,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
|
||||
IsAutoPush = trackPushConfig.IsAutoPush,
|
||||
IsCanUpdate = trackPushConfig.IsCanUpdate,
|
||||
IsAllPush = trackPushConfig.IsAllPush,
|
||||
IsAllPushWithLatest = trackPushConfig.IsAllPushWithLatest,
|
||||
IsCanDelete = trackPushConfig.IsCanDelete,
|
||||
DateTimeFormatType = (int) trackPushConfig.DateTimeFormatType,
|
||||
DateTimeFormat = trackPushConfig.DateTimeFormat,
|
||||
@ -89,6 +91,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
|
||||
TrackContentValue = item.TrackContentValue,
|
||||
TrackEnContentValue = item.TrackEnContentValue,
|
||||
TrackTimeZone = item.TrackTimeZone,
|
||||
// todo:废弃字段如果没有外部子系统依赖,可以逐步删除
|
||||
ExpandFieldsValue = item.ExpandFieldsValue,
|
||||
}).ToList();
|
||||
|
||||
|
||||
@ -142,7 +142,8 @@ public class SjzyTrackApplicationModule : AbpModule
|
||||
options.PoolSize = configuration.GetValue<int>("RabbitMQ:PoolSize");
|
||||
options.Declarations = new List<Action<IDeclaration>>()
|
||||
{
|
||||
o=>o.ExchangeDeclare(GlobalConst.TrackChangeExchange, ExchangeType.Topic, true),
|
||||
o => o.ExchangeDeclare(GlobalConst.TrackChangeExchange, ExchangeType.Topic, true),
|
||||
o => o.ExchangeDeclare(GlobalConst.TrackPushExchange, ExchangeType.Topic, true)
|
||||
};
|
||||
options.Consumes = new List<ConsumeOptions>
|
||||
{
|
||||
@ -158,6 +159,19 @@ public class SjzyTrackApplicationModule : AbpModule
|
||||
o.QueueBind(GlobalConst.TrackRefreshSubscribe, GlobalConst.InterfaceRelayExchange,
|
||||
GlobalConst.TrackRefreshSubscribe);
|
||||
}
|
||||
},
|
||||
new()
|
||||
{
|
||||
Queue = GlobalConst.TrackPushCompletedSubscribe,
|
||||
FetchCount = configuration.GetValue<ushort>("TrackApp:TrackRefreshFetchCount"),
|
||||
FailedRequeue = false,
|
||||
Declaration = o =>
|
||||
{
|
||||
o.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true);
|
||||
o.QueueDeclare(GlobalConst.TrackPushCompletedSubscribe, true);
|
||||
o.QueueBind(GlobalConst.TrackPushCompletedSubscribe, GlobalConst.InterfaceRelayExchange,
|
||||
GlobalConst.TrackPushCompletedSubscribe);
|
||||
}
|
||||
}
|
||||
};
|
||||
}, typeof(SjzyTrackApplicationModule).Assembly);
|
||||
|
||||
@ -9,6 +9,21 @@ public interface IOrderOperationRecordEsRepository
|
||||
/// <returns></returns>
|
||||
Task AddAsync(OrderOperationRecordIndex index);
|
||||
|
||||
/// <summary>
|
||||
/// 添加订单操作记录(批量)
|
||||
/// </summary>
|
||||
/// <param name="indexes"></param>
|
||||
/// <returns></returns>
|
||||
Task AddManyAsync(List<OrderOperationRecordIndex> indexes);
|
||||
|
||||
/// <summary>
|
||||
/// 根据id删除订单操作记录
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="indexName"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteOperationRecordByIdAsync(string id, string indexName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取订单操作记录
|
||||
/// </summary>
|
||||
|
||||
@ -12,7 +12,7 @@ public interface IOrderRepository : IBasicRepository<OrderEntity>
|
||||
/// <returns></returns>
|
||||
Task<UnifyPageResultDto<TrackOrderVO>> GetTrackOrderPagedList(GetPageTrackOrderInputVO input);
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// 通过三方平台和三方单号查询订单
|
||||
/// </summary>
|
||||
/// <param name="serviceProvidrCode">三方平台</param>
|
||||
@ -62,6 +62,27 @@ public interface IOrderRepository : IBasicRepository<OrderEntity>
|
||||
/// <returns></returns>
|
||||
Task<List<(string code, int id)>> GetSubSystemListByCodesAsync(List<string> codes);
|
||||
|
||||
#region 订单模板
|
||||
|
||||
/// <summary>
|
||||
/// 根据订单id,获取订单所属的模板
|
||||
/// </summary>
|
||||
/// <param name="orderId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<OrderTemplateVO>> GetOrderTemplateAsync(int[] orderId);
|
||||
|
||||
/// <summary>
|
||||
/// 根据子系统+订单号+类型,获取订单所属的模板
|
||||
/// </summary>
|
||||
/// <param name="subSystemId"></param>
|
||||
/// <param name="orderType"></param>
|
||||
/// <param name="orderNos"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<OrderTemplateVO>> GetOrderTemplateAsync(int subSystemId,int orderType,List<string> orderNos);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 订单关联
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -10,7 +10,7 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
|
||||
|
||||
Task<List<TrackDetailsIndex>> GetLatestListAsync(int[] eventOrderIds, List<string> trackCodes);
|
||||
|
||||
Task<List<TrackDetailsIndex>> GetListAsync(int subSystemId, int orderType, List<string> orderNos);
|
||||
Task<List<TrackDetailsIndex>> GetListAsync(int subSystemId, int orderType, List<string> orderNos, List<string>? trackCodes = null);
|
||||
|
||||
Task<bool> AnyAsync(int orderId, string originTrackDataHash);
|
||||
|
||||
@ -31,6 +31,8 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
|
||||
Task<List<int>> DeleteTrackAsync(int[] orderIds, List<string> trackCodes);
|
||||
|
||||
Task DeleteTrackByIdAsync(string id, string indexName);
|
||||
|
||||
Task<List<TrackDetailsIndex>> GetDataByIds(string[] ids);
|
||||
|
||||
Task<TrackDetailsIndex> GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime);
|
||||
}
|
||||
|
||||
@ -190,5 +190,5 @@ public class TrackDetailsIndex : IdBaseIndex
|
||||
/// <summary>
|
||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||
/// </summary>
|
||||
public Dictionary<string, object>? Extra { get; set; }
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
|
||||
@ -11,6 +11,14 @@ public interface ITrackPushRecordEsRepository
|
||||
|
||||
Task AddManyAsync(List<TrackPushRecordIndex> index);
|
||||
|
||||
/// <summary>
|
||||
/// 根据id删除轨迹推送记录
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="indexName"></param>
|
||||
/// <returns></returns>
|
||||
Task DeletePushRecordByIdAsync(string id, string indexName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取轨迹推送记录
|
||||
/// </summary>
|
||||
@ -22,6 +30,14 @@ public interface ITrackPushRecordEsRepository
|
||||
/// 获取最新轨迹推送记录
|
||||
/// </summary>
|
||||
/// <param name="orderId"></param>
|
||||
/// <param name="isSuccess">只选择成功的记录</param>
|
||||
/// <returns></returns>
|
||||
Task<TrackPushRecordIndex?> GetLatestTrackPushRecordAsync(int orderId);
|
||||
Task<TrackPushRecordIndex?> GetLatestTrackPushRecordAsync(int orderId, bool isSuccess = false);
|
||||
|
||||
/// <summary>
|
||||
/// 获取历史中推送成功的记录
|
||||
/// </summary>
|
||||
/// <param name="orderId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<TrackPushRecordIndex>> GetHistorySuccessTrackPushRecordAsync(int orderId);
|
||||
}
|
||||
|
||||
@ -56,6 +56,12 @@ public class TrackPushConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot
|
||||
[SugarColumn(ColumnName = "IsAllPush")]
|
||||
public bool IsAllPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否全量推送(最新轨迹)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "IsAllPushWithLatest")]
|
||||
public bool IsAllPushWithLatest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日期时间格式类型
|
||||
/// </summary>
|
||||
|
||||
@ -82,4 +82,19 @@ public class TrackPushRecordIndex : IdBaseIndex
|
||||
|
||||
/// <summary>创建时间</summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子系统代码
|
||||
/// </summary>
|
||||
public string SubSystemCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否广播
|
||||
/// </summary>
|
||||
public bool IsToMq { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹额外信息
|
||||
/// </summary>
|
||||
public string? Extra { get; set; }
|
||||
}
|
||||
|
||||
@ -45,6 +45,8 @@ public interface ITrackTemplateRepository : IBasicRepository<TrackTemplateEntity
|
||||
Expression<Func<TrackTemplateContentEntity, bool>> whereExpression);
|
||||
|
||||
Task<List<TrackTemplateOutputVo>> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input);
|
||||
|
||||
Task<UnifyPageResultDto<TemplateContentDtoVo>> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input);
|
||||
|
||||
Task<List<string>> GetContentByTemplateCodes(string[] codes, int systemId);
|
||||
}
|
||||
|
||||
@ -57,5 +57,8 @@ public partial class GlobalConst
|
||||
/// </summary>
|
||||
public const string TrackChangeExchange = "sjzy.track.on_track_change_ex";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 轨迹推送通知交换机
|
||||
/// </summary>
|
||||
public const string TrackPushExchange = "sjzy.track.on_track_push_ex";
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ public partial class GlobalConst
|
||||
{
|
||||
public const string MainDataKey_OrderType = "TrackOrderType";
|
||||
public const string MainDataKey_TrackQuestionType = "TrackQuestionType";
|
||||
public const string HTTP_HEADER_SUBSYSTEMID = "Subsystemid";
|
||||
public const string SystemUser = "系统";
|
||||
public const string EmptyString = "--";
|
||||
public const int ChunkSize = 100;
|
||||
|
||||
13
src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs
Normal file
13
src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace SJZY.Track.Domain.Dtos.Order;
|
||||
|
||||
/// <summary>
|
||||
/// 订单关联的模板模型
|
||||
/// </summary>
|
||||
public class OrderTemplateVO
|
||||
{
|
||||
public int OrderId { get; set; }
|
||||
|
||||
public string OrderNo { get; set; }
|
||||
|
||||
public string? TemplateCodes { get; set; }
|
||||
}
|
||||
@ -2,6 +2,11 @@ namespace SJZY.Track.Domain.Dtos.TrackContents;
|
||||
|
||||
public class TrackContentVO
|
||||
{
|
||||
/// <summary>
|
||||
/// 子系统Id
|
||||
/// </summary>
|
||||
public int SubSystemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子系统代码
|
||||
/// </summary>
|
||||
|
||||
@ -51,6 +51,11 @@ public class GetTrackPushConfigDetailOutputVO
|
||||
/// </summary>
|
||||
public bool IsAllPush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否全量推送(最新轨迹)
|
||||
/// </summary>
|
||||
public bool IsAllPushWithLatest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间格式枚举
|
||||
/// </summary>
|
||||
|
||||
@ -54,4 +54,9 @@ public class TemplateContentDtoVo
|
||||
/// 轨迹节点
|
||||
/// </summary>
|
||||
public string Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序键
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
}
|
||||
|
||||
@ -8,17 +8,17 @@ namespace SJZY.Track.Domain.Enums;
|
||||
public enum TrackSourceEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 外部服务商创建
|
||||
/// 外部服务商
|
||||
/// </summary>
|
||||
[Description("外部服务商创建")] ExternalServiceProvide = 1,
|
||||
[Description("外部服务商")] ExternalServiceProvide = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 内部系统创建
|
||||
/// 内部系统
|
||||
/// </summary>
|
||||
[Description("内部系统创建")] InternalService = 2,
|
||||
[Description("内部系统")] InternalService = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 人工创建
|
||||
/// 人工
|
||||
/// </summary>
|
||||
[Description("人工创建")] Artificial = 3,
|
||||
[Description("人工")] Artificial = 3,
|
||||
}
|
||||
|
||||
@ -52,6 +52,14 @@ public interface IProvideQueries
|
||||
/// <returns></returns>
|
||||
Task<TrackContentVO?> GetTrackContentAsync(int subSystemId, string trackCode);
|
||||
|
||||
/// <summary>
|
||||
/// 获取轨迹内容
|
||||
/// </summary>
|
||||
/// <param name="subSystemIds">子系统ids</param>
|
||||
/// <param name="trackCodes">轨迹代码集合</param>
|
||||
/// <returns></returns>
|
||||
Task<List<TrackContentVO>> GetTrackContentsAsync(int[] subSystemIds, string[] trackCodes);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有拉取配置
|
||||
/// </summary>
|
||||
|
||||
7
src/SJZY.Track.Domain/Queries/IVSystemQueries.cs
Normal file
7
src/SJZY.Track.Domain/Queries/IVSystemQueries.cs
Normal file
@ -0,0 +1,7 @@
|
||||
using SJZY.Track.Domain.VEntities;
|
||||
|
||||
namespace SJZY.Track.Domain.Queries;
|
||||
|
||||
public interface IVSystemQueries : IBasicQuery<VSystemEntity>
|
||||
{
|
||||
}
|
||||
@ -4,7 +4,7 @@ namespace SJZY.Track.Domain.VEntities;
|
||||
///
|
||||
/// </summary>
|
||||
[SugarTable("v_system")]
|
||||
public class VSystemEntity : IFullAuditedBasicEntitys
|
||||
public class VSystemEntity : IFullAuditedBasicEntitys, IEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 子系统id
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackFlagAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackPullAggregate;
|
||||
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
||||
using SJZY.Track.Domain.Dtos.Order;
|
||||
@ -99,24 +100,52 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, ITransientDepen
|
||||
return await Context.Queryable<TrackContentEntity>()
|
||||
.LeftJoin<TrackStatusEntity>((x, y) => x.TrackStatusId == y.Id)
|
||||
.LeftJoin<VSystemEntity>((x, y, z) => x.SubSystemId == z.Id)
|
||||
.LeftJoin<TrackFlagEntity>((x, y, z, k) => x.SubSystemId == k.SubSystemId && k.Code == x.Code)
|
||||
.Where(x => x.SubSystemId == subSystemId && x.Code == trackCode)
|
||||
.Select((x, y, z) => new TrackContentVO
|
||||
.Select((x, y, z, k) => new TrackContentVO
|
||||
{
|
||||
SubSystemCode = z.Key,
|
||||
TrackStatusId = x.TrackStatusId,
|
||||
TrackStatus = y.Status,
|
||||
TrackStatusCode = y.Code,
|
||||
TrackContentCode = x.Code,
|
||||
TrackContent = x.Content,
|
||||
TrackEnContent = x.EnContent,
|
||||
IsCompleted = y.IsCompleted,
|
||||
IsRepeatable = x.IsRepeatable,
|
||||
IsAllowManuallyUpdate = x.IsAllowManuallyUpdate,
|
||||
IsAllowManuallyCreate = x.IsAllowManuallyCreate,
|
||||
IsToMq = y.IsToMq,
|
||||
IsToMq = y.IsToMq || k.IsToMq,
|
||||
})
|
||||
.FirstAsync();
|
||||
}
|
||||
|
||||
public async Task<List<TrackContentVO>> GetTrackContentsAsync(int[] subSystemIds, string[] trackCodes)
|
||||
{
|
||||
return await Context.Queryable<TrackContentEntity>()
|
||||
.LeftJoin<TrackStatusEntity>((x, y) => x.TrackStatusId == y.Id)
|
||||
.LeftJoin<VSystemEntity>((x, y, z) => x.SubSystemId == z.Id)
|
||||
.LeftJoin<TrackFlagEntity>((x, y, z, k) => x.SubSystemId == k.SubSystemId && k.Code == x.Code)
|
||||
.Where(x => subSystemIds.Contains(x.SubSystemId) && trackCodes.Contains(x.Code))
|
||||
.Select((x, y, z, k) => new TrackContentVO
|
||||
{
|
||||
SubSystemId = x.SubSystemId,
|
||||
SubSystemCode = z.Key,
|
||||
TrackStatusId = x.TrackStatusId,
|
||||
TrackStatus = y.Status,
|
||||
TrackStatusCode = y.Code,
|
||||
TrackContentCode = x.Code,
|
||||
TrackContent = x.Content,
|
||||
TrackEnContent = x.EnContent,
|
||||
IsCompleted = y.IsCompleted,
|
||||
IsRepeatable = x.IsRepeatable,
|
||||
IsAllowManuallyUpdate = x.IsAllowManuallyUpdate,
|
||||
IsAllowManuallyCreate = x.IsAllowManuallyCreate,
|
||||
IsToMq = y.IsToMq || k.IsToMq,
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<TrackPullConfigVo>> GetAllPullConfigsAsync()
|
||||
{
|
||||
return await Context.Queryable<TrackPullConfigEntity>()
|
||||
|
||||
8
src/SJZY.Track.Repository/Queries/VSystemQueries.cs
Normal file
8
src/SJZY.Track.Repository/Queries/VSystemQueries.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using SJZY.Track.Domain.Queries;
|
||||
using SJZY.Track.Domain.VEntities;
|
||||
|
||||
namespace SJZY.Track.Repository.Queries;
|
||||
|
||||
public class VSystemQueries : BasicQuery<VSystemEntity>, IVSystemQueries, ITransientDependency
|
||||
{
|
||||
}
|
||||
@ -29,6 +29,36 @@ public class OrderOperationRecordEsRepository : ElasticSearchContextAbstract<Ord
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddManyAsync(List<OrderOperationRecordIndex> indexes)
|
||||
{
|
||||
// 按天写入es
|
||||
var indexName = $"{GlobalConst.OrderOperationRecordIndex}-{DateTime.Now:yyyy.MM.dd}";
|
||||
indexes.ForEach(x =>
|
||||
{
|
||||
x.IndexName = indexName;
|
||||
x.CreateTime = DateTime.Now;
|
||||
});
|
||||
|
||||
var r = await Context.IndexManyAsync(indexes, indexName);
|
||||
|
||||
if (!r.IsValid)
|
||||
{
|
||||
throw new InvalidOperationException($"{indexes.Count}条订单变更记录写入失败,原因:{r.DebugInformation}。");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteOperationRecordByIdAsync(string id, string indexName)
|
||||
{
|
||||
var r = await Context.DeleteAsync<OrderOperationRecordIndex>(id, u => u
|
||||
.Index(indexName)
|
||||
);
|
||||
|
||||
if (!r.IsValid)
|
||||
{
|
||||
throw new InvalidOperationException($"轨迹操作记录失败,id:{indexName},原因:{r.DebugInformation}。");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<OrderOperationRecordIndex>> GetOrderOperationsByIdAsync(int orderId)
|
||||
{
|
||||
var data = await Context.SearchAsync<OrderOperationRecordIndex>(x => x
|
||||
@ -39,6 +69,6 @@ public class OrderOperationRecordEsRepository : ElasticSearchContextAbstract<Ord
|
||||
.Size(GlobalConst.NormalLimit)
|
||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
||||
|
||||
return data.Documents.ToList();
|
||||
return data.ToIdList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using NUglify.Helpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using SJZY.Expand.ABP.Core.Logger;
|
||||
using SJZY.Track.Domain;
|
||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||
@ -11,56 +11,64 @@ namespace SJZY.Track.Repository.Repositories;
|
||||
|
||||
public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, ITransientDependency
|
||||
{
|
||||
public async Task<UnifyPageResultDto<TrackOrderVO>> GetTrackOrderPagedList(GetPageTrackOrderInputVO input)
|
||||
//MemoryCache本身线程安全简单使用,短暂数据不一致可以容忍,每过固定时间强制清除缓存
|
||||
private static readonly MemoryCache _memoryCache = new(new MemoryCacheOptions());
|
||||
private static readonly Dictionary<int, string> _empty = new();
|
||||
private static readonly Dictionary<string, Dictionary<int, string>> _empty2 = new();
|
||||
private const int ThirdPartyOrderNumberCacheTimeSpan = 3 * 60;
|
||||
private const int MainDataEnumCacheTimeSpan = 5 * 60;
|
||||
|
||||
private async Task<Dictionary<int, string>> GetThirdPartyOrderNumberForCacheAsync(int[] orderIds)
|
||||
{
|
||||
//查询完去重
|
||||
var pageList = await Context.Queryable<OrderEntity>()
|
||||
const string key = "ThirdPartyOrderNumber";
|
||||
if (orderIds.Length == 0) return _empty;
|
||||
|
||||
var dict = _memoryCache.Get<Dictionary<int, string>>(key);
|
||||
|
||||
orderIds = orderIds.Distinct().ToArray();
|
||||
if (dict != null && dict.Count != 0 && !orderIds.Except(dict.Keys).Any()) return dict;
|
||||
|
||||
var orders = await Context.Queryable<OrderEntity>()
|
||||
.Includes(a => a.OrderPlatformNumbers)
|
||||
.LeftJoin<VExternalSubjectEntity>((a, b) => a.CustomId == b.Id && b.IsDeleted == false)
|
||||
.LeftJoin<VSystemEntity>((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false)
|
||||
.LeftJoin<OrderPlatformNumberEntity>((a, b, c, d) => a.Id == d.OrderId && d.IsDeleted == false)
|
||||
.WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId)
|
||||
.WhereIF(!input.OrderNos.IsNullOrEmpty(), (a, b, c, d) => input.OrderNos!.Contains(a.OrderNo) || input.OrderNos!.Contains(d.OrderNumber))
|
||||
.WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue,
|
||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd)
|
||||
.WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue),
|
||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart)
|
||||
.WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue,
|
||||
(a, b, c) => a.CreateTime <= input.CreateTimeEnd)
|
||||
.WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId)
|
||||
.WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType)
|
||||
.WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType)
|
||||
.WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted)
|
||||
.OrderByDescending((a, b, c) => a.CreateTime)
|
||||
.Distinct()
|
||||
.Select((a, b, c) => new TrackOrderVO
|
||||
.LeftJoin<OrderPlatformNumberEntity>((a, b) => a.Id == b.OrderId && b.IsDeleted == false)
|
||||
.Where((a, b) => orderIds.Contains(a.Id))
|
||||
.Select(a => new OrderEntity()
|
||||
{
|
||||
Id = a.Id,
|
||||
OrderNumber = a.OrderNo,
|
||||
OrderType = a.OrderType,
|
||||
QuestionType = a.QuestionType,
|
||||
CustomerShortName = b.Abbreviation,
|
||||
CustomerCode = b.Code,
|
||||
CustomerId = a.CustomId,
|
||||
NewestTrackContent = a.LatestTrackContent,
|
||||
NewestTrackEnContent = a.LatestTrackEnContent,
|
||||
NewestTrackPlace = a.LatestTrackPlace,
|
||||
NewestTrackTime = a.LatestTrackTime,
|
||||
IsFinish = a.IsCompleted,
|
||||
CreateTime = a.CreateTime,
|
||||
SubSystem = c.CnName,
|
||||
SubSystemId = c.Id,
|
||||
DestinationTimeZone = a.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = a.EstimatedDeliveryDate,
|
||||
ThirdPartyOrderNumber = BuildThirdPartyOrderNumber(a.OrderPlatformNumbers)
|
||||
OrderPlatformNumbers = a.OrderPlatformNumbers
|
||||
})
|
||||
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
||||
.ToListAsync();
|
||||
|
||||
if (orders.Count == 0)
|
||||
return _empty;
|
||||
|
||||
orders = orders.DistinctBy(x => x.Id).ToList();
|
||||
|
||||
dict = orders.ToDictionary(x => x.Id, x => BuildThirdPartyOrderNumber(x.OrderPlatformNumbers));
|
||||
|
||||
_memoryCache.Set(key, dict, new MemoryCacheEntryOptions
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(ThirdPartyOrderNumberCacheTimeSpan),
|
||||
Size = dict.Count
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, Dictionary<int, string>>> GetMainDataEnumForCacheAsync(List<int> orderTypes, List<int> questTypes)
|
||||
{
|
||||
const string key = "EnumForMainData";
|
||||
if (orderTypes.Count == 0 && questTypes.Count == 0) return _empty2;
|
||||
|
||||
var dict = _memoryCache.Get<Dictionary<string, Dictionary<int, string>>>(key);
|
||||
if (dict != null && dict.Count != 0
|
||||
&& !orderTypes.Except(dict[GlobalConst.MainDataKey_OrderType].Keys).Any()
|
||||
&& !questTypes.Except(dict[GlobalConst.MainDataKey_TrackQuestionType].Keys).Any())
|
||||
{
|
||||
return dict;
|
||||
}
|
||||
|
||||
//查询订单类型描述
|
||||
var orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList();
|
||||
var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList();
|
||||
//从主数据中心查询类型描述
|
||||
var typeDispDict = (await Context.Queryable<VEnumValueInfoEntity>()
|
||||
dict = (await Context.Queryable<VEnumValueInfoEntity>()
|
||||
.Where(x =>
|
||||
(x.Property == GlobalConst.MainDataKey_OrderType && orderTypes.Contains(x.Enumkey))
|
||||
|| (x.Property == GlobalConst.MainDataKey_TrackQuestionType && questTypes.Contains(x.Enumkey))
|
||||
@ -79,20 +87,161 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
|
||||
y => y.ToDictionary(x => x.Enumkey, x => x.Disp)
|
||||
);
|
||||
|
||||
if (dict.Count == 0)
|
||||
return _empty2;
|
||||
|
||||
_memoryCache.Set(key, dict, new MemoryCacheEntryOptions
|
||||
{
|
||||
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(MainDataEnumCacheTimeSpan),
|
||||
Size = dict.Count
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
|
||||
public async Task<UnifyPageResultDto<TrackOrderVO>> GetTrackOrderPagedList(GetPageTrackOrderInputVO input)
|
||||
{
|
||||
//查询完去重
|
||||
UnifyPageResultDto<TrackOrderVO> pageList;
|
||||
//没传递单号时
|
||||
if (input.OrderNos.IsNullOrEmpty())
|
||||
{
|
||||
pageList = await Context.Queryable<OrderEntity>()
|
||||
.LeftJoin<VExternalSubjectEntity>((a, b) => a.CustomId == b.Id && b.IsDeleted == false)
|
||||
.LeftJoin<VSystemEntity>((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false)
|
||||
.WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId)
|
||||
.WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue,
|
||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd)
|
||||
.WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue),
|
||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart)
|
||||
.WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue,
|
||||
(a, b, c) => a.CreateTime <= input.CreateTimeEnd)
|
||||
.WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId)
|
||||
.WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType)
|
||||
.WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType)
|
||||
.WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted)
|
||||
.OrderByDescending((a, b, c) => a.CreateTime)
|
||||
.Select((a, b, c) => new TrackOrderVO
|
||||
{
|
||||
Id = a.Id,
|
||||
OrderNumber = a.OrderNo,
|
||||
OrderType = a.OrderType,
|
||||
QuestionType = a.QuestionType,
|
||||
CustomerShortName = b.Abbreviation,
|
||||
CustomerCode = b.Code,
|
||||
CustomerId = a.CustomId,
|
||||
NewestTrackContent = a.LatestTrackContent,
|
||||
NewestTrackEnContent = a.LatestTrackEnContent,
|
||||
NewestTrackPlace = a.LatestTrackPlace,
|
||||
NewestTrackTime = a.LatestTrackTime,
|
||||
IsFinish = a.IsCompleted,
|
||||
CreateTime = a.CreateTime,
|
||||
SubSystem = c.CnName,
|
||||
SubSystemId = c.Id,
|
||||
DestinationTimeZone = a.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = a.EstimatedDeliveryDate
|
||||
})
|
||||
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
||||
}
|
||||
//传递单号时
|
||||
else
|
||||
{
|
||||
var orderNos = input.OrderNos!.Distinct().ToList();
|
||||
|
||||
//匹配主单
|
||||
var orderIds = await Context.Queryable<OrderEntity>()
|
||||
.Where(x => orderNos.Contains(x.OrderNo))
|
||||
.Select(x => x.Id)
|
||||
.ToListAsync();
|
||||
|
||||
//匹配外部单
|
||||
var orderIdsForThirdParty = await Context.Queryable<OrderPlatformNumberEntity>()
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber) && orderNos.Contains(x.OrderNumber))
|
||||
.Select(x => x.OrderId)
|
||||
.ToListAsync();
|
||||
|
||||
var orderHashset = orderIds.ToHashSet();
|
||||
orderHashset.UnionWith(orderIdsForThirdParty);
|
||||
orderIds = orderHashset.ToList();
|
||||
|
||||
//没有任何单
|
||||
if (orderIds.Count == 0)
|
||||
{
|
||||
return new UnifyPageResultDto<TrackOrderVO>
|
||||
{
|
||||
List = new List<TrackOrderVO>(),
|
||||
Pagination = new PageInfoOutput()
|
||||
{
|
||||
PageIndex = input.PageIndex,
|
||||
PageSize = input.PageSize,
|
||||
Total = 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pageList = await Context.Queryable<OrderEntity>()
|
||||
.Where(x => orderIds.Contains(x.Id))
|
||||
.LeftJoin<VExternalSubjectEntity>((a, b) => a.CustomId == b.Id && b.IsDeleted == false)
|
||||
.LeftJoin<VSystemEntity>((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false)
|
||||
.WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId)
|
||||
.WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue,
|
||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd)
|
||||
.WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue),
|
||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart)
|
||||
.WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue,
|
||||
(a, b, c) => a.CreateTime <= input.CreateTimeEnd)
|
||||
.WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId)
|
||||
.WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType)
|
||||
.WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType)
|
||||
.WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted)
|
||||
.OrderByDescending((a, b, c) => a.CreateTime)
|
||||
.Select((a, b, c) => new TrackOrderVO
|
||||
{
|
||||
Id = a.Id,
|
||||
OrderNumber = a.OrderNo,
|
||||
OrderType = a.OrderType,
|
||||
QuestionType = a.QuestionType,
|
||||
CustomerShortName = b.Abbreviation,
|
||||
CustomerCode = b.Code,
|
||||
CustomerId = a.CustomId,
|
||||
NewestTrackContent = a.LatestTrackContent,
|
||||
NewestTrackEnContent = a.LatestTrackEnContent,
|
||||
NewestTrackPlace = a.LatestTrackPlace,
|
||||
NewestTrackTime = a.LatestTrackTime,
|
||||
IsFinish = a.IsCompleted,
|
||||
CreateTime = a.CreateTime,
|
||||
SubSystem = c.CnName,
|
||||
SubSystemId = c.Id,
|
||||
DestinationTimeZone = a.DestinationTimeZone,
|
||||
EstimatedDeliveryDate = a.EstimatedDeliveryDate,
|
||||
})
|
||||
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
||||
}
|
||||
|
||||
|
||||
//补三方单号,从缓存中加速查
|
||||
var orderIdArr = pageList.List.Select(x => x.Id).ToArray();
|
||||
var thirdPartyOrderNumbers = await GetThirdPartyOrderNumberForCacheAsync(orderIdArr);
|
||||
pageList.List.ForEach(x => x.ThirdPartyOrderNumber = thirdPartyOrderNumbers[x.Id]);
|
||||
|
||||
//查询订单类型描述,从缓存中加速查
|
||||
var orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList();
|
||||
var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList();
|
||||
var typeDisplayDict = await GetMainDataEnumForCacheAsync(orderTypes, questTypes);
|
||||
|
||||
//填充数描述信息
|
||||
pageList.List.ForEach(x =>
|
||||
{
|
||||
x.OrderTypeName = typeDispDict.TryGetValue(GlobalConst.MainDataKey_OrderType, out var orderTypeDisplayDict)
|
||||
x.OrderTypeName = typeDisplayDict.TryGetValue(GlobalConst.MainDataKey_OrderType, out var orderTypeDisplayDict)
|
||||
? orderTypeDisplayDict.TryGetValue(x.OrderType, out var orderTypeDisplay)
|
||||
? orderTypeDisplay
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]"
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]";
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] "
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] EnumKey:[{x.OrderType}]";
|
||||
|
||||
x.QuestionTypeName = typeDispDict.TryGetValue(GlobalConst.MainDataKey_TrackQuestionType, out var questDisplayDict)
|
||||
x.QuestionTypeName = typeDisplayDict.TryGetValue(GlobalConst.MainDataKey_TrackQuestionType, out var questDisplayDict)
|
||||
? questDisplayDict.TryGetValue(x.QuestionType, out var questDisplay)
|
||||
? questDisplay
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]"
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}]";
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]"
|
||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}] EnumKey:[{x.OrderType}]";
|
||||
});
|
||||
|
||||
return pageList;
|
||||
@ -247,6 +396,32 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
|
||||
return res.Select(x => (x.Key, x.Id)).ToList();
|
||||
}
|
||||
|
||||
public Task<List<OrderTemplateVO>> GetOrderTemplateAsync(int[] orderId)
|
||||
{
|
||||
return Context.Queryable<OrderEntity>()
|
||||
.Where(x => orderId.Contains(x.Id))
|
||||
.Select(a => new OrderTemplateVO
|
||||
{
|
||||
OrderId = a.Id,
|
||||
OrderNo = a.OrderNo,
|
||||
TemplateCodes = a.TemplateCodes
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<List<OrderTemplateVO>> GetOrderTemplateAsync(int subSystemId, int orderType, List<string> orderNos)
|
||||
{
|
||||
return Context.Queryable<OrderEntity>()
|
||||
.Where(x => orderNos.Contains(x.OrderNo) && x.SubSystemId == subSystemId && x.OrderType == orderType)
|
||||
.Select(a => new OrderTemplateVO
|
||||
{
|
||||
OrderId = a.Id,
|
||||
OrderNo = a.OrderNo,
|
||||
TemplateCodes = a.TemplateCodes
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<VSystemEntity> GetSystemInfoById(int id)
|
||||
{
|
||||
return Context.Queryable<VSystemEntity>().FirstAsync(m => m.IsDeleted == false && m.Id == id);
|
||||
@ -274,12 +449,15 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
|
||||
/// </summary>
|
||||
/// <param name="orderPlatformNumberEntities"></param>
|
||||
/// <returns></returns>
|
||||
private static string BuildThirdPartyOrderNumber(List<OrderPlatformNumberEntity> orderPlatformNumberEntities)
|
||||
public string BuildThirdPartyOrderNumber(List<OrderPlatformNumberEntity> orderPlatformNumberEntities)
|
||||
{
|
||||
if (orderPlatformNumberEntities.Count == 0) return GlobalConst.EmptyString;
|
||||
const string separator = "、";
|
||||
var thirdPartyOrderNumbers = orderPlatformNumberEntities
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber))
|
||||
.Select(x => $"{x.OrderNumber}({x.Platform})").ToList();
|
||||
.Select(x => $"{x.OrderNumber}({x.Platform})")
|
||||
.ToList();
|
||||
if (thirdPartyOrderNumbers.Count == 0) return GlobalConst.EmptyString;
|
||||
return string.Join(separator, thirdPartyOrderNumbers);
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ using SJZY.Expand.ABP.Core.PublicMethords;
|
||||
using SJZY.Expand.ElasticSearch.Services;
|
||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||
using SJZY.Track.Domain.Consts;
|
||||
using SJZY.Track.Domain.Dtos.TrackContents;
|
||||
using SJZY.Track.Domain.Enums;
|
||||
|
||||
namespace SJZY.Track.Repository.Repositories;
|
||||
@ -20,7 +19,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
||||
public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode,
|
||||
bool forUpsert = false)
|
||||
{
|
||||
var r = !forUpsert
|
||||
var r = forUpsert
|
||||
? await Context.SearchAsync<TrackDetailsIndex>(s => s
|
||||
.Index(GlobalConst.TrackDetailsIndex)
|
||||
.Source()
|
||||
@ -373,36 +372,38 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<TrackDetailsIndex>> GetListAsync(int subSystemId, int orderType, List<string> orderNos)
|
||||
public async Task<List<TrackDetailsIndex>> GetListAsync(int subSystemId, int orderType, List<string> orderNos, List<string>? trackCodes = null)
|
||||
{
|
||||
if (orderNos.Count < 1) return new List<TrackDetailsIndex>();
|
||||
|
||||
var musts = new List<Func<QueryContainerDescriptor<TrackDetailsIndex>, QueryContainer>>
|
||||
{
|
||||
mu => mu.Term(f => f.SubSystemId, subSystemId),
|
||||
mu => mu
|
||||
.Terms(t => t
|
||||
.Field(f => f.OrderNo.Suffix("keyword"))
|
||||
.Terms(orderNos)
|
||||
),
|
||||
mu => mu
|
||||
.Term(f => f.OrderType, orderType)
|
||||
};
|
||||
|
||||
if (trackCodes != null && trackCodes.Count > 0)
|
||||
{
|
||||
musts.Add(mu => mu
|
||||
.Terms(t => t
|
||||
.Field(f => f.TrackCode.Suffix("keyword"))
|
||||
.Terms(trackCodes)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
var r = await Context.SearchAsync<TrackDetailsIndex>(x => x
|
||||
.Index(GlobalConst.TrackDetailsIndex)
|
||||
.Source(s => s.Includes(fd => fd
|
||||
.Field(f => f.OrderId)
|
||||
.Field(f => f.OrderNo)
|
||||
.Field(f => f.TrackStatus)
|
||||
.Field(f => f.TrackCode)
|
||||
.Field(f => f.TrackContent)
|
||||
.Field(f => f.OriginTrackContent)
|
||||
.Field(f => f.TrackPlace)
|
||||
.Field(f => f.TrackTime)
|
||||
.Field(f => f.ZeroTrackTime)
|
||||
.Field(f => f.TrackTimeZone)
|
||||
))
|
||||
.Source()
|
||||
.Query(q =>
|
||||
q.Bool(b => b
|
||||
.Must(
|
||||
mu => mu.Term(f => f.SubSystemId, subSystemId),
|
||||
mu => mu
|
||||
.Terms(t => t
|
||||
.Field(f => f.OrderNo.Suffix("keyword"))
|
||||
.Terms(orderNos)
|
||||
),
|
||||
mu => mu
|
||||
.Term(f => f.OrderType, orderType)
|
||||
)
|
||||
.Must(musts)
|
||||
// tips:对外不暴露服务商轨迹
|
||||
.MustNot(mn => mn
|
||||
.Term(t => t.TrackCode.Suffix("keyword"), GlobalConst.EmptyString)
|
||||
@ -418,7 +419,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
||||
$"轨迹查询失败,orderType:{orderType},orderNos:{orderNos},原因:{r.DebugInformation}。");
|
||||
}
|
||||
|
||||
return r.Documents.ToList();
|
||||
return r.ToIdList();
|
||||
}
|
||||
|
||||
public async Task<List<TrackDetailsIndex>> GetListAsync(int orderId)
|
||||
@ -429,7 +430,10 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
||||
q.Term(t => t.OrderId, orderId)
|
||||
)
|
||||
.Size(SafelyLimit)
|
||||
.Sort(s => s.Field(f => f.ZeroTrackTime, SortOrder.Descending)));
|
||||
.Sort(s => s
|
||||
.Field(f => f.ZeroTrackTime, SortOrder.Descending)
|
||||
.Field(f => f.CreateTime, SortOrder.Descending)
|
||||
));
|
||||
|
||||
if (!r.IsValid)
|
||||
{
|
||||
@ -462,7 +466,10 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
||||
.Index(GlobalConst.TrackDetailsIndex)
|
||||
.Query(q => query)
|
||||
.Size(SafelyLimit)
|
||||
.Sort(s => s.Field(f => f.ZeroTrackTime, SortOrder.Descending)));
|
||||
.Sort(s => s
|
||||
.Field(f => f.ZeroTrackTime, SortOrder.Descending)
|
||||
.Field(f => f.CreateTime, SortOrder.Descending))
|
||||
);
|
||||
|
||||
if (!r.IsValid)
|
||||
{
|
||||
|
||||
@ -45,6 +45,18 @@ public class TrackPushRecordEsRepository : ElasticSearchContextAbstract<TrackPus
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeletePushRecordByIdAsync(string id, string indexName)
|
||||
{
|
||||
var r = await Context.DeleteAsync<TrackPushRecordIndex>(id, u => u
|
||||
.Index(indexName)
|
||||
);
|
||||
|
||||
if (!r.IsValid)
|
||||
{
|
||||
throw new InvalidOperationException($"轨迹推送记录失败,id:{indexName},原因:{r.DebugInformation}。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<TrackPushRecordIndex>> GetTrackPushRecordsAsync(int orderId)
|
||||
{
|
||||
@ -56,19 +68,46 @@ public class TrackPushRecordEsRepository : ElasticSearchContextAbstract<TrackPus
|
||||
.Size(1000)
|
||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
||||
|
||||
return data.Documents.ToList();
|
||||
return data.ToIdList();
|
||||
}
|
||||
|
||||
public async Task<TrackPushRecordIndex?> GetLatestTrackPushRecordAsync(int orderId)
|
||||
public async Task<TrackPushRecordIndex?> GetLatestTrackPushRecordAsync(int orderId, bool isSuccess = false)
|
||||
{
|
||||
var musts = new List<Func<QueryContainerDescriptor<TrackPushRecordIndex>, QueryContainer>>
|
||||
{
|
||||
mu => mu.Term(t => t.OrderId, orderId),
|
||||
};
|
||||
|
||||
if (isSuccess)
|
||||
musts.Add(mu => mu.Term(t => t.IsSuccess, true));
|
||||
|
||||
var data = await Context.SearchAsync<TrackPushRecordIndex>(x => x
|
||||
.Index(GlobalConst.TrackPushRecordIndex)
|
||||
.Query(q =>
|
||||
q.Term(t => t.OrderId, orderId)
|
||||
q.Bool(b =>
|
||||
b.Must(musts))
|
||||
)
|
||||
.Size(1000)
|
||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
||||
|
||||
return data.Documents.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task<List<TrackPushRecordIndex>> GetHistorySuccessTrackPushRecordAsync(int orderId)
|
||||
{
|
||||
var data = await Context.SearchAsync<TrackPushRecordIndex>(x => x
|
||||
.Index(GlobalConst.TrackPushRecordIndex)
|
||||
.Source(s =>
|
||||
s.Excludes(fs =>
|
||||
fs.Field(f => f.PushContent)))
|
||||
.Query(q => q.Bool(b =>
|
||||
b.Must(
|
||||
mu => mu.Term(t => t.IsSuccess, true),
|
||||
mu => mu.Term(t => t.OrderId, orderId)
|
||||
))
|
||||
)
|
||||
.Size(1000)
|
||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
||||
return data.ToIdList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,7 +214,8 @@ public class TrackTemplateRepository : BasicRepository<TrackTemplateEntity>, ITr
|
||||
ContentCn = b.Content,
|
||||
ContentEn = b.EnContent,
|
||||
Status = c.Status,
|
||||
Node = d.NodeName
|
||||
Node = d.NodeName,
|
||||
Sort = a.Sort
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
@ -222,7 +223,8 @@ public class TrackTemplateRepository : BasicRepository<TrackTemplateEntity>, ITr
|
||||
{
|
||||
var templateContents = contents.Where(x => x.TemplateId == template.Id).ToList();
|
||||
|
||||
template.TemplateContents = templateContents;
|
||||
//根据排序键排序
|
||||
template.TemplateContents = templateContents.OrderBy(x => x.Sort).ToList();
|
||||
}
|
||||
|
||||
return templates;
|
||||
@ -262,10 +264,13 @@ public class TrackTemplateRepository : BasicRepository<TrackTemplateEntity>, ITr
|
||||
ContentCn = b.Content,
|
||||
ContentEn = b.EnContent,
|
||||
Status = c.Status,
|
||||
Node = d.NodeName
|
||||
Node = d.NodeName,
|
||||
Sort = a.Sort
|
||||
})
|
||||
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
||||
|
||||
//返回轨迹模板内容时按排序键排序
|
||||
contents.List = contents.List.OrderBy(x => x.Sort).ToList();
|
||||
return contents;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user