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": {
|
"Configuration": {
|
||||||
"UseLocalConfiguration": true,
|
"UseLocalConfiguration": false,
|
||||||
//是否使用本地配置文件
|
//是否使用本地配置文件
|
||||||
"ConfiguraFileName": "appsettings.Development.json",
|
"ConfiguraFileName": "appsettings.Development.json",
|
||||||
//指定配置文件名称,开启UseLocalConfiguration时生效
|
//指定配置文件名称,开启UseLocalConfiguration时生效
|
||||||
"Apollo": {
|
"Apollo": {
|
||||||
"AppId": "SJZY.Track.Configuration",
|
"AppId": "SJZY.Track.Configuration",
|
||||||
"Env": "DEV",
|
"Env": "DEV",
|
||||||
"Namespace": "dev",
|
"Namespace": "test",
|
||||||
"MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080",
|
"MetaServer": "https://apollo.test.shijizhongyun.com",
|
||||||
"ConfigServer": [
|
"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]
|
[Required]
|
||||||
[MaxLength(500)]
|
[MaxLength(500)]
|
||||||
public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = new();
|
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)]
|
[Range(-12, 12)]
|
||||||
public float? DestinationTimeZone { get; set; }
|
public float? DestinationTimeZone { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重复的情况下,用什么比较
|
||||||
|
/// </summary>
|
||||||
|
public string? CompareFields { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||||
/// </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
|
public class DeleteTrackInput : OrderNoInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 轨迹标识符集合,必填
|
/// 轨迹标识符集合,为支持esid删除,所以非必填
|
||||||
/// </summary>
|
/// </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;
|
namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 支持模板,传入时区补正,按轨迹发生时间升序降序
|
||||||
|
/// </summary>
|
||||||
public class GetTrackInput : OrderNosInfo
|
public class GetTrackInput : OrderNosInfo
|
||||||
{
|
{
|
||||||
private float? _timeZone;
|
private float? _timeZone;
|
||||||
@ -8,12 +11,19 @@ public class GetTrackInput : OrderNosInfo
|
|||||||
/// 时区 +8 +8.25 -8.5 -9
|
/// 时区 +8 +8.25 -8.5 -9
|
||||||
/// 不传默认+8
|
/// 不传默认+8
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float? TimeZone
|
public float? TimeZone { get => _timeZone ?? 8; set => _timeZone = value; }
|
||||||
{
|
|
||||||
get => _timeZone ?? 8;
|
/// <summary>
|
||||||
set => _timeZone = value;
|
/// 排序方式,默认按轨迹发生时间降序
|
||||||
|
/// </summary>
|
||||||
|
public SortMethod? SortMethod { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不支持模板,无时区补正,按轨迹发生时间升序降序
|
||||||
|
/// </summary>
|
||||||
|
public class GetTrackInputV2 : OrderNosInfo
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排序方式,默认按轨迹发生时间降序
|
/// 排序方式,默认按轨迹发生时间降序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -25,10 +35,20 @@ public enum SortMethod
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 按轨迹发生时间排序
|
/// 按轨迹发生时间排序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ByTrackTime,
|
ByTrackTime = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 按轨迹发生时间降序
|
/// 按轨迹发生时间降序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ByTrackTimeDesc,
|
ByTrackTimeDesc = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模板排序+轨迹发生时间
|
||||||
|
/// </summary>
|
||||||
|
ByTemplateAndTrackTime = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模板排序+轨迹发生时间
|
||||||
|
/// </summary>
|
||||||
|
ByTemplateAndTrackTimeDesc = 3
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ public class GetTrackOutput
|
|||||||
|
|
||||||
public class TrackDetail
|
public class TrackDetail
|
||||||
{
|
{
|
||||||
|
public string EsId { get; set; } = null!;
|
||||||
public string Code { get; set; } = null!;
|
public string Code { get; set; } = null!;
|
||||||
public string Status { get; set; } = null!;
|
public string Status { get; set; } = null!;
|
||||||
public string? Content { get; set; }
|
public string? Content { get; set; }
|
||||||
@ -91,7 +92,6 @@ public class TrackDetail
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? TrackPlacePostcode { get; set; }
|
public string? TrackPlacePostcode { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预计到达时间
|
/// 预计到达时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -105,5 +105,5 @@ public class TrackDetail
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, object>? Extra { get; set; }
|
public string? Extra { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,4 +9,14 @@ public class PushTrackInput : OrderNosInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
public string TrackCode { get; set; } = null!;
|
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>
|
/// </summary>
|
||||||
public string Node { get; set; }
|
public string Node { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序键
|
||||||
|
/// </summary>
|
||||||
|
public int Sort { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ public class UpdateOrderInput : OrderNoInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 模板code
|
/// 模板code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> TemplateCodes { get; set; }
|
public List<string>? TemplateCodes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PullConfigInfo
|
public class PullConfigInfo
|
||||||
|
|||||||
@ -9,6 +9,11 @@ public class UpsertTrackInput : OrderNoInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAdd { get; set; }
|
public bool IsAdd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轨迹唯一标识(可选)
|
||||||
|
/// </summary>
|
||||||
|
public string? EsId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 轨迹内容代码
|
/// 轨迹内容代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -27,7 +32,7 @@ public class UpsertTrackInput : OrderNoInfo
|
|||||||
/// 轨迹发生时间
|
/// 轨迹发生时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime? TrackTime { get; set; }
|
public DateTime TrackTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更改后的轨迹发生时间,无需更改保持为空
|
/// 更改后的轨迹发生时间,无需更改保持为空
|
||||||
@ -124,8 +129,23 @@ public class UpsertTrackInput : OrderNoInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int OptionUserId { get; set; }
|
public int OptionUserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重复的情况下,用什么比较
|
||||||
|
/// </summary>
|
||||||
|
public string? CompareFields { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||||
/// </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; }
|
public string? OrderNo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 操作类型 1=创建 2=修改 3=删除
|
/// 操作类型 1=创建 2=修改 3=删除 4=推送
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TrackOptionType TrackOptionType { get; set; }
|
public TrackOptionType TrackOptionType { get; set; }
|
||||||
}
|
}
|
||||||
@ -22,5 +22,6 @@ public enum TrackOptionType
|
|||||||
{
|
{
|
||||||
创建 = 1,
|
创建 = 1,
|
||||||
修改 = 2,
|
修改 = 2,
|
||||||
删除 = 3
|
删除 = 3,
|
||||||
|
推送 = 4,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,10 +44,15 @@ public class EditTrackPushConfigInput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? IsAllPush { get; set; }
|
public bool? IsAllPush { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否全量推送
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsAllPushWithLatest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 时间格式枚举
|
/// 时间格式枚举
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int DateTimeFormatType { get; set; }
|
public int? DateTimeFormatType { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 日期时间格式模板
|
/// 日期时间格式模板
|
||||||
|
|||||||
@ -17,6 +17,11 @@ public class TrackPushContentConfigDto
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAllPush { get; set; }
|
public bool IsAllPush { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否全量推送(最新轨迹)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAllPushWithLatest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否支持删除
|
/// 是否支持删除
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -70,6 +75,7 @@ public class TrackPushContentConfigDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展字段参数值
|
/// 扩展字段参数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("废弃属性,调整为从轨迹明细扩展中获取扩展值填入")]
|
||||||
public string? ExpandFieldsValue { get; set; }
|
public string? ExpandFieldsValue { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -4,7 +4,8 @@ public class TrackPushInput
|
|||||||
{
|
{
|
||||||
public string OrderNo { get; set; } = null!;
|
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 string Log { get; set; }
|
||||||
}
|
}
|
||||||
@ -13,19 +14,8 @@ public class TrackUpdateInput
|
|||||||
{
|
{
|
||||||
public string OrderNo { get; set; } = null!;
|
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 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>
|
/// </summary>
|
||||||
public DateTime? EstimatedDeliveryDate { get; set; }
|
public DateTime? EstimatedDeliveryDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||||
|
/// </summary>
|
||||||
|
public string? Extra { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,17 +12,27 @@ public class TrackDeleteEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// es中的id
|
/// es中的id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] EsIds { get; set; }
|
public string[]? EsIds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 订单ids
|
/// 订单ids
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int[] OrderIds { get; set; } = null!;
|
public int[] OrderIds { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重复的情况下,用什么字段比较
|
||||||
|
/// </summary>
|
||||||
|
public string? CompareFields { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重复的情况下,比较值
|
||||||
|
/// </summary>
|
||||||
|
public object? CompareValue { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 轨迹标识符
|
/// 轨迹标识符
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = null!;
|
public List<TrackIdentifierDto>? TrackIdentifiers { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public SystemPushStruct SystemPushInfo { get; set; }
|
public SystemPushStruct SystemPushInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否强制推送
|
||||||
|
/// </summary>
|
||||||
|
public bool ForcedPush { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否发送到mq
|
||||||
|
/// </summary>
|
||||||
|
public bool IsToMq { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct SystemPushStruct
|
public struct SystemPushStruct
|
||||||
@ -69,4 +79,14 @@ public struct SystemPushStruct
|
|||||||
/// 轨迹发生时区
|
/// 轨迹发生时区
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float TrackTimeZone { get; set; }
|
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>
|
/// </summary>
|
||||||
public OrderIdentifier[] OrderIdentifiers { get; set; } = null!;
|
public OrderIdentifier[] OrderIdentifiers { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轨迹唯一标识(用于单个订单更新单条轨迹,如果有的话优先级最高)
|
||||||
|
/// </summary>
|
||||||
|
public string? EsId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 操作人(null则默认系统)
|
/// 操作人(null则默认系统)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -141,10 +146,25 @@ public class TrackUpsertEvent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float? DestinationTimeZone { get; set; }
|
public float? DestinationTimeZone { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重复的情况下,用什么比较
|
||||||
|
/// </summary>
|
||||||
|
public string? CompareFields { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||||
/// </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()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<Version>7.0.3</Version>
|
<Version>7.0.14</Version>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<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>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<string> PushTrackAsync(PushTrackInput input);
|
public Task<UnifyResultDto> PushTrackAsync(PushTrackInput input);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取轨迹推送内容
|
/// 获取轨迹推送内容
|
||||||
@ -20,12 +20,12 @@ public interface ITrackPushService : IRemoteService
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <param name="subSystemId">子系统id</param>
|
/// <param name="subSystemId">子系统id</param>
|
||||||
/// <param name="customerId">客户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>
|
||||||
/// 获取轨迹推送记录
|
/// 获取轨迹推送记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <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>
|
/// <returns></returns>
|
||||||
Task<UnifyResultDto> UpsertTrackAsync(UpsertTrackInput input);
|
Task<UnifyResultDto> UpsertTrackAsync(UpsertTrackInput input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量新增/更新订单轨迹接口
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<UnifyResultDto> BatchUpsertTrackAsync(BatchUpsertTrackInput input);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除轨迹
|
/// 删除轨迹
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -28,8 +35,17 @@ public interface ITrackService : IRemoteService
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据订单号获取轨迹
|
/// 根据订单号获取轨迹
|
||||||
|
/// 支持模板,传入时区补正,按轨迹发生时间升序降序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<UnifyResultDto<List<GetTrackOutput>>> QueryAsync(GetTrackInput input);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//指示是否需要更新【预计签收时间】【签收地时区】
|
|
||||||
var isNeedUpdate = false;
|
|
||||||
var updateOrders = new List<OrderEntity>();
|
var updateOrders = new List<OrderEntity>();
|
||||||
foreach (var order in orders)
|
foreach (var order in orders)
|
||||||
{
|
{
|
||||||
@ -62,15 +60,12 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
|
|||||||
{
|
{
|
||||||
order.EstimatedDeliveryDate = @event.EstimatedDeliveryDate.Value;
|
order.EstimatedDeliveryDate = @event.EstimatedDeliveryDate.Value;
|
||||||
order.DestinationTimeZone = @event.DestinationTimeZone.Value;
|
order.DestinationTimeZone = @event.DestinationTimeZone.Value;
|
||||||
isNeedUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOrders.Add(order);
|
updateOrders.Add(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _orderRepository.UpdateRangeAsync(updateOrders,
|
await _orderRepository.UpdateRangeAsync(updateOrders, x => new
|
||||||
isNeedUpdate
|
|
||||||
? x => new
|
|
||||||
{
|
{
|
||||||
x.IsCompleted,
|
x.IsCompleted,
|
||||||
x.LatestTrackContent,
|
x.LatestTrackContent,
|
||||||
@ -79,20 +74,9 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
|
|||||||
x.LatestTrackTime,
|
x.LatestTrackTime,
|
||||||
x.LatestTrackTimeZone,
|
x.LatestTrackTimeZone,
|
||||||
x.DeficiencyTag,
|
x.DeficiencyTag,
|
||||||
//当标识指示需要更新时添加更新列
|
|
||||||
x.EstimatedDeliveryDate,
|
x.EstimatedDeliveryDate,
|
||||||
x.DestinationTimeZone
|
x.DestinationTimeZone
|
||||||
}
|
}
|
||||||
: x => new
|
|
||||||
{
|
|
||||||
x.IsCompleted,
|
|
||||||
x.LatestTrackContent,
|
|
||||||
x.LatestTrackEnContent,
|
|
||||||
x.LatestTrackPlace,
|
|
||||||
x.LatestTrackTime,
|
|
||||||
x.LatestTrackTimeZone,
|
|
||||||
x.DeficiencyTag,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +93,8 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
|
|||||||
LatestTrackPlace = order.LatestTrackPlace,
|
LatestTrackPlace = order.LatestTrackPlace,
|
||||||
LatestTrackTime = order.LatestTrackTime,
|
LatestTrackTime = order.LatestTrackTime,
|
||||||
LatestTrackTimeZone = order.LatestTrackTimeZone,
|
LatestTrackTimeZone = order.LatestTrackTimeZone,
|
||||||
|
DestinationTimeZone = order.DestinationTimeZone,
|
||||||
|
EstimatedDeliveryDate = order.EstimatedDeliveryDate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
using System.Text;
|
using System.Collections.Immutable;
|
||||||
using BSI.Stack.Rabbit;
|
using System.Text.Json;
|
||||||
using DotNetCore.CAP;
|
using DotNetCore.CAP;
|
||||||
using SJZY.Expand.ABP.Core.Logger;
|
using SJZY.Expand.ABP.Core.Logger;
|
||||||
using SJZY.Expand.ABP.Core.PublicMethords;
|
using SJZY.Expand.ABP.Core.PublicMethords;
|
||||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||||
using SJZY.Track.Application.Contract.Events;
|
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.OrderAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
|
||||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
|
||||||
using SJZY.Track.Domain.Enums;
|
using SJZY.Track.Domain.Enums;
|
||||||
using SJZY.Track.Domain.Queries;
|
using SJZY.Track.Domain.Queries;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
@ -18,30 +18,24 @@ namespace SJZY.Track.Application.CAP.EventHandlers;
|
|||||||
public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
||||||
{
|
{
|
||||||
private readonly ICapPublisher _capPublisher;
|
private readonly ICapPublisher _capPublisher;
|
||||||
|
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly ITrackStatusRepository _trackStatusRepository;
|
|
||||||
private readonly ITrackContentRepository _trackContentRepository;
|
|
||||||
private readonly IProvideQueries _provideQueries;
|
private readonly IProvideQueries _provideQueries;
|
||||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||||
private readonly RabbitClientBus _rabbitClientBus;
|
private readonly IBroadcastingService _broadcastingService;
|
||||||
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
|
||||||
|
|
||||||
public TrackDeleteEventHandler(IProvideQueries provideQueries,
|
public TrackDeleteEventHandler(IProvideQueries provideQueries,
|
||||||
IOrderRepository orderRepository, ICapPublisher capPublisher,
|
IOrderRepository orderRepository, ICapPublisher capPublisher,
|
||||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||||
RabbitClientBus rabbitClientBus,
|
IOrderOperationRecordEsRepository orderOperationRecordEsRepository,
|
||||||
ITrackStatusRepository trackStatusRepository,
|
IBroadcastingService broadcastingService)
|
||||||
ITrackContentRepository trackContentRepository,
|
|
||||||
IOrderOperationRecordEsRepository orderOperationRecordEsRepository)
|
|
||||||
{
|
{
|
||||||
_provideQueries = provideQueries;
|
_provideQueries = provideQueries;
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_capPublisher = capPublisher;
|
_capPublisher = capPublisher;
|
||||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||||
_rabbitClientBus = rabbitClientBus;
|
|
||||||
_trackStatusRepository = trackStatusRepository;
|
|
||||||
_trackContentRepository = trackContentRepository;
|
|
||||||
_orderOperationRecordEsRepository = orderOperationRecordEsRepository;
|
_orderOperationRecordEsRepository = orderOperationRecordEsRepository;
|
||||||
|
_broadcastingService = broadcastingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)]
|
[CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)]
|
||||||
@ -51,8 +45,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
|
|
||||||
var trackList = await DeleteTrackAsync(@event);
|
var trackList = await DeleteTrackAsync(@event);
|
||||||
|
|
||||||
//发布事件
|
//当轨迹删除,根据轨迹标记/状态上IsToMq选择进行广播
|
||||||
await PublicTrackTopicAsync(@event, trackList);
|
if (trackList.Count != 0)
|
||||||
|
_ = PublicTrackTopicAsync(@event, trackList);
|
||||||
|
|
||||||
// 根据订单关联关系异步向下刷(异步)
|
// 根据订单关联关系异步向下刷(异步)
|
||||||
await DownByOrderLink(@event);
|
await DownByOrderLink(@event);
|
||||||
@ -126,51 +121,6 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
return true;
|
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)
|
private async Task<List<TrackDetailsIndex>> DeleteTrackAsync(TrackDeleteEvent @event)
|
||||||
{
|
{
|
||||||
List<int> orderIds;
|
List<int> orderIds;
|
||||||
@ -208,10 +158,40 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
//根据订单查询出所有的轨迹,查所有是因为主单上需要进行回退更新
|
//根据订单查询出所有的轨迹,查所有是因为主单上需要进行回退更新
|
||||||
tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds);
|
tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds);
|
||||||
|
|
||||||
|
//比较字段为空则使用时间来作为额外的标识key
|
||||||
|
if (string.IsNullOrWhiteSpace(@event.CompareFields))
|
||||||
|
{
|
||||||
//构建标识符集合
|
//构建标识符集合
|
||||||
var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToList();
|
var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToHashSet();
|
||||||
//根据标识符选出要删除的轨迹明细
|
//根据标识符选出要删除的轨迹明细
|
||||||
deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList();
|
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;
|
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),
|
var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id),
|
||||||
x => new OrderEntity
|
x => new OrderEntity
|
||||||
@ -267,21 +248,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
order.EstimatedDeliveryDate = track.EstimatedDeliveryDate;
|
order.EstimatedDeliveryDate = track.EstimatedDeliveryDate;
|
||||||
order.DestinationTimeZone = track.DestinationTimeZone;
|
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,
|
await _orderRepository.UpdateRangeAsync(orders,
|
||||||
x => new
|
x => new
|
||||||
{
|
{
|
||||||
@ -294,6 +263,104 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
x.DestinationTimeZone
|
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;
|
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 DotNetCore.CAP;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -23,23 +25,28 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
private readonly IHttpClientProxy<IInterfaceForwardServiceV2> _httpClientProxy;
|
private readonly IHttpClientProxy<IInterfaceForwardServiceV2> _httpClientProxy;
|
||||||
private readonly IOptionsMonitor<InterfaceRelayParamsConfigOptions> _options;
|
private readonly IOptionsMonitor<InterfaceRelayParamsConfigOptions> _options;
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
|
||||||
private readonly ITrackPushCacheService _trackPushCacheService;
|
private readonly ITrackPushCacheService _trackPushCacheService;
|
||||||
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
||||||
|
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||||
|
private readonly IBroadcastingService _broadcastingService;
|
||||||
private List<OrderEntity> _orders = null!;
|
private List<OrderEntity> _orders = null!;
|
||||||
private List<TrackPushContentConfigDto> _pushConfigs = null!;
|
private List<TrackPushContentConfigDto> _pushConfigs = null!;
|
||||||
|
|
||||||
public TrackPushEventHandler(IHttpClientProxy<IInterfaceForwardServiceV2> httpClientProxy,
|
public TrackPushEventHandler(IHttpClientProxy<IInterfaceForwardServiceV2> httpClientProxy,
|
||||||
IOrderRepository orderRepository, ITrackPushCacheService trackPushCacheService,
|
IOrderRepository orderRepository,
|
||||||
ITrackDetailsEsRepository trackDetailsEsRepository, ITrackPushRecordEsRepository trackPushRecordEsRepository,
|
ITrackPushCacheService trackPushCacheService,
|
||||||
IOptionsMonitor<InterfaceRelayParamsConfigOptions> options)
|
ITrackPushRecordEsRepository trackPushRecordEsRepository,
|
||||||
|
IOptionsMonitor<InterfaceRelayParamsConfigOptions> options,
|
||||||
|
IBroadcastingService broadcastingService,
|
||||||
|
ITrackDetailsEsRepository trackDetailsEsRepository)
|
||||||
{
|
{
|
||||||
_httpClientProxy = httpClientProxy;
|
_httpClientProxy = httpClientProxy;
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_trackPushCacheService = trackPushCacheService;
|
_trackPushCacheService = trackPushCacheService;
|
||||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
|
||||||
_trackPushRecordEsRepository = trackPushRecordEsRepository;
|
_trackPushRecordEsRepository = trackPushRecordEsRepository;
|
||||||
_options = options;
|
_options = options;
|
||||||
|
_broadcastingService = broadcastingService;
|
||||||
|
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CapSubscribe(GlobalConst.TrackPushSubscribe, Group = GlobalConst.TrackPushSubscribe)]
|
[CapSubscribe(GlobalConst.TrackPushSubscribe, Group = GlobalConst.TrackPushSubscribe)]
|
||||||
@ -67,6 +74,13 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
if (orders.Count == 0) return;
|
if (orders.Count == 0) return;
|
||||||
_orders = orders;
|
_orders = orders;
|
||||||
|
|
||||||
|
if (@event.ForcedPush)
|
||||||
|
{
|
||||||
|
//当为强制推送,会走手动推送逻辑
|
||||||
|
await DoPushAsync(@event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (@event.OptionType)
|
switch (@event.OptionType)
|
||||||
{
|
{
|
||||||
case OptionType.无:
|
case OptionType.无:
|
||||||
@ -86,76 +100,22 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
|
|
||||||
private async Task DoPushAsync(TrackPushEvent @event)
|
private async Task DoPushAsync(TrackPushEvent @event)
|
||||||
{
|
{
|
||||||
var items = new List<object>();
|
var items = new List<TrackPushInput>();
|
||||||
TrackPushContentConfigDto? config;
|
|
||||||
|
|
||||||
if (@event.OperationMan == null)
|
if (@event.OperationMan == null)
|
||||||
{
|
{
|
||||||
foreach (var order in _orders)
|
if (@event.OptionType == OptionType.新增)
|
||||||
{
|
{
|
||||||
if (order.QuestionType == (int) TrackProblemType.Error) continue; // 系统不推异常单,只能人工操作
|
await BuiltSystemPushItemsAsync(@event, items);
|
||||||
// 推送新增,需要根据上一次的推送 推断 本次推送 是否可行
|
}
|
||||||
config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event.TrackCode);
|
else if (@event.OptionType == OptionType.修改)
|
||||||
if (config == null) continue;
|
|
||||||
if (!config.IsAutoPush) continue;
|
|
||||||
if (config.OrderType != order.OrderType) continue;
|
|
||||||
|
|
||||||
var log = new TrackPushRecordIndex
|
|
||||||
{
|
{
|
||||||
OptionType = @event.OptionType.ToString(),
|
await BuiltManualPushItemsAsync(@event, items);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //手工推送
|
else
|
||||||
{
|
{
|
||||||
config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode);
|
// 手工推送,不会校验已推和顺序问题,因为可能是更新
|
||||||
if (config == null) return;
|
await BuiltManualPushItemsAsync(@event, items);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items.Count == 0) return;
|
if (items.Count == 0) return;
|
||||||
@ -164,26 +124,119 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode)))
|
new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode)))
|
||||||
{
|
{
|
||||||
var asciiString = Base64Helper.SerializeObject(OptionType.新增.ToString());
|
var asciiString = Base64Helper.SerializeObject(OptionType.新增.ToString());
|
||||||
|
var serviceProviderCode = _pushConfigs.First().ServiceProviderCode;
|
||||||
var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
|
var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
|
||||||
_options.CurrentValue.PushTrackInterfaceCode,
|
_options.CurrentValue.PushTrackInterfaceCode,
|
||||||
_pushConfigs.First().ServiceProviderCode, items, GlobalConst.TrackPushCompletedSubscribe,
|
serviceProviderCode, items.Cast<object>().ToList(), GlobalConst.TrackPushCompletedSubscribe,
|
||||||
attach: asciiString);
|
attach: asciiString);
|
||||||
|
|
||||||
if (r.Code != GlobalConst.SuccessCode)
|
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);
|
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)
|
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
|
var log = new TrackPushRecordIndex
|
||||||
{
|
{
|
||||||
OptionType = @event.OptionType.ToString(),
|
OptionType = @event.OptionType.ToString(),
|
||||||
@ -196,6 +249,47 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
TrackTime = @event.SystemPushInfo.TrackTime,
|
TrackTime = @event.SystemPushInfo.TrackTime,
|
||||||
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
TrackTimeZone = @event.SystemPushInfo.TrackTimeZone,
|
||||||
CreateUser = GlobalConst.SystemUser,
|
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);
|
var item = BuiltUpdateItem(config, log);
|
||||||
item.Log = JsonConvert.SerializeObject(log);
|
item.Log = JsonConvert.SerializeObject(log);
|
||||||
@ -208,14 +302,18 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode)))
|
new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode)))
|
||||||
{
|
{
|
||||||
var asciiString = Base64Helper.SerializeObject(OptionType.修改.ToString());
|
var asciiString = Base64Helper.SerializeObject(OptionType.修改.ToString());
|
||||||
|
var serviceProviderCode = _pushConfigs.First().ServiceProviderCode;
|
||||||
var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
|
var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync(
|
||||||
_options.CurrentValue.TrackUpdateInterfaceCode,
|
_options.CurrentValue.TrackUpdateInterfaceCode,
|
||||||
_pushConfigs.First().ServiceProviderCode, items, GlobalConst.TrackPushCompletedSubscribe,
|
serviceProviderCode, items.Cast<object>().ToList(), GlobalConst.TrackPushCompletedSubscribe,
|
||||||
attach: asciiString);
|
attach: asciiString);
|
||||||
|
|
||||||
if (r.Code != GlobalConst.SuccessCode)
|
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 trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone);
|
||||||
var trackDateStr = DateTimeFormat(trackDatetime, config.TrackTimeZone ?? log.TrackTimeZone, config);
|
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
|
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();
|
log.PushContent = body.ToJson();
|
||||||
|
|
||||||
return body;
|
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 trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone);
|
||||||
var trackDateStr = DateTimeFormat(trackDatetime, config.TrackTimeZone ?? log.TrackTimeZone, config);
|
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
|
var body = new TrackPushInput
|
||||||
{
|
{
|
||||||
OrderNo = log.OrderNo,
|
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)
|
if (config.IsAllPush)
|
||||||
{
|
{
|
||||||
var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId);
|
var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId, true);
|
||||||
if (history != default)
|
if (history != default)
|
||||||
{
|
{
|
||||||
body = JsonConvert.DeserializeObject<TrackPushInput>(history.PushContent);
|
body = TextJsonHelper.Deserialize<TrackPushInput>(history.PushContent);
|
||||||
body!.Data.Add(track);
|
|
||||||
|
//在推送历史中,选出当前轨迹明细一致的轨迹
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.PushContent = body.ToJson();
|
// 添加当前要推送的轨迹
|
||||||
|
body.Data.Add(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.PushContent = TextJsonHelper.Serialize(body)!;
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
@ -291,35 +445,34 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
/// 根据轨迹代码推断下一个(升序)要推送的内容,如果找不到或者已经是最后一个了
|
/// 根据轨迹代码推断下一个(升序)要推送的内容,如果找不到或者已经是最后一个了
|
||||||
/// 则查询有没有可交换的推送,没有就返回null
|
/// 则查询有没有可交换的推送,没有就返回null
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cache"></param>
|
private static TrackPushContentConfigDto? GetValidPushConfigAsync(List<TrackPushContentConfigDto> cache,
|
||||||
/// <param name="latestPushTrackCode"></param>
|
string? latestPushTrackCode, TrackPushEvent @event)
|
||||||
/// <param name="trackCode"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
TrackPushContentConfigDto? GetValidPushConfigAsync(List<TrackPushContentConfigDto> cache,
|
|
||||||
string? latestPushTrackCode, string? trackCode)
|
|
||||||
{
|
{
|
||||||
|
var trackCode = @event.TrackCode;
|
||||||
var idx = cache.FindIndex(x => x.TrackCode == latestPushTrackCode);
|
var idx = cache.FindIndex(x => x.TrackCode == latestPushTrackCode);
|
||||||
|
|
||||||
|
if (@event.ForcedPush && trackCode == latestPushTrackCode)
|
||||||
|
{
|
||||||
|
//强制推送,允许重复推送当前轨迹
|
||||||
|
return cache[idx];
|
||||||
|
}
|
||||||
|
|
||||||
if (idx + 1 >= cache.Count) return default; // 推完了
|
if (idx + 1 >= cache.Count) return default; // 推完了
|
||||||
|
|
||||||
// find next
|
// find next
|
||||||
var matched = cache[idx + 1].TrackCode == trackCode
|
var matched = cache[idx + 1].TrackCode == trackCode
|
||||||
? cache[idx + 1]
|
? cache[idx + 1]
|
||||||
:
|
|
||||||
// find swap
|
// find swap
|
||||||
cache.FirstOrDefault(x => x.TrackCode == cache[idx + 1].SwapTrackCode);
|
: cache.FirstOrDefault(x => x.TrackCode == cache[idx + 1].SwapTrackCode);
|
||||||
|
|
||||||
|
//没推完,可能不符合推送顺序
|
||||||
return matched != null && matched.TrackCode == trackCode ? matched : default;
|
return matched != null && matched.TrackCode == trackCode ? matched : default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换推送时间格式
|
/// 转换推送时间格式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dateTime"></param>
|
private static string DateTimeFormat(DateTime dateTime, double timezone, TrackPushContentConfigDto config)
|
||||||
/// <param name="timezone"></param>
|
|
||||||
/// <param name="config"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string DateTimeFormat(DateTime dateTime, double timezone, TrackPushContentConfigDto config)
|
|
||||||
{
|
{
|
||||||
if (config.DateTimeFormatType == (int) DateTimeFormatEnum.Timestamp)
|
if (config.DateTimeFormatType == (int) DateTimeFormatEnum.Timestamp)
|
||||||
return DateTimeHelper.ConvertToUnixTimestamp(dateTime).ToString();
|
return DateTimeHelper.ConvertToUnixTimestamp(dateTime).ToString();
|
||||||
@ -335,4 +488,61 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
|
|
||||||
return dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK");
|
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 System.Diagnostics;
|
||||||
using BSI.Stack.Rabbit;
|
|
||||||
using DotNetCore.CAP;
|
using DotNetCore.CAP;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using SJZY.Expand.ABP.Core.Logger;
|
using SJZY.Expand.ABP.Core.Logger;
|
||||||
using SJZY.Expand.ABP.Core.PublicMethords;
|
using SJZY.Expand.ABP.Core.PublicMethords;
|
||||||
using SJZY.Track.Application.Contract.Events;
|
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.OrderAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
|
||||||
using SJZY.Track.Domain.Dtos.TrackContents;
|
using SJZY.Track.Domain.Dtos.TrackContents;
|
||||||
using SJZY.Track.Domain.Enums;
|
using SJZY.Track.Domain.Enums;
|
||||||
using SJZY.Track.Domain.Queries;
|
using SJZY.Track.Domain.Queries;
|
||||||
@ -21,7 +22,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly IProvideQueries _provideQueries;
|
private readonly IProvideQueries _provideQueries;
|
||||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||||
private readonly RabbitClientBus _rabbitClientBus;
|
private readonly IBroadcastingService _broadcastingService;
|
||||||
|
private readonly ILogger<TrackUpsertEventHandler> _logger;
|
||||||
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository;
|
||||||
|
|
||||||
public TrackUpsertEventHandler(
|
public TrackUpsertEventHandler(
|
||||||
@ -29,15 +31,17 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
ICapPublisher capPublisher,
|
ICapPublisher capPublisher,
|
||||||
IProvideQueries provideQueries,
|
IProvideQueries provideQueries,
|
||||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||||
RabbitClientBus rabbitClientBus,
|
IOrderOperationRecordEsRepository orderOperationRecordEsRepository,
|
||||||
IOrderOperationRecordEsRepository orderOperationRecordEsRepository)
|
IBroadcastingService broadcastingService,
|
||||||
|
ILogger<TrackUpsertEventHandler> logger)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_capPublisher = capPublisher;
|
_capPublisher = capPublisher;
|
||||||
_provideQueries = provideQueries;
|
_provideQueries = provideQueries;
|
||||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||||
_rabbitClientBus = rabbitClientBus;
|
|
||||||
_orderOperationRecordEsRepository = orderOperationRecordEsRepository;
|
_orderOperationRecordEsRepository = orderOperationRecordEsRepository;
|
||||||
|
_broadcastingService = broadcastingService;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)]
|
[CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)]
|
||||||
@ -51,59 +55,14 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
var content = await HandleTrackAsync(@event, canNextOrderIds);
|
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;
|
if (canNextOrderIds.Count == 0) return;
|
||||||
// 根据订单关联关系异步向下刷(异步)
|
// 根据订单关联关系异步向下刷(异步)
|
||||||
await DownByOrderLink(@event, canNextOrderIds);
|
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)
|
private async Task DownByOrderLink(TrackUpsertEvent @event, List<int> canNextOrderIds)
|
||||||
{
|
{
|
||||||
// 根据订单关联关系异步向下刷(异步)
|
// 根据订单关联关系异步向下刷(异步)
|
||||||
@ -185,6 +144,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: 在这里,判断存在性
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +178,14 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
// 批量add to es
|
// 批量add to es
|
||||||
await _trackDetailsEsRepository.AddManyAsync(insertTracks);
|
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(),
|
await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(),
|
||||||
@event.TrackCode);
|
@event.TrackCode);
|
||||||
@ -262,8 +231,12 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
TrackContent = trackContent.TrackContent,
|
TrackContent = trackContent.TrackContent,
|
||||||
TrackPlace = @event.TrackPlace,
|
TrackPlace = @event.TrackPlace,
|
||||||
TrackTime = @event.NewTrackTime ?? @event.TrackTime,
|
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);
|
await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent);
|
||||||
|
|
||||||
@ -276,68 +249,139 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray();
|
var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray();
|
||||||
|
|
||||||
// important:轨迹code相同,时间、发生地不同的,可能存在多条!!
|
// 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 insertTracks = new List<TrackDetailsIndex>();
|
||||||
var updateTracks = new List<TrackDetailsIndex>();
|
var updateTracks = new List<TrackDetailsIndex>();
|
||||||
|
var operationRecords = new List<OrderOperationRecordIndex>();
|
||||||
foreach (var order in @event.OrderIdentifiers)
|
foreach (var order in @event.OrderIdentifiers)
|
||||||
{
|
{
|
||||||
TrackDetailsIndex? track;
|
// fast path: by update with es id case
|
||||||
if (!@event.IsAdd)
|
if (!@event.IsAdd && !string.IsNullOrWhiteSpace(@event.EsId))
|
||||||
{
|
{
|
||||||
//同一订单同轨迹code同一轨迹时间如果有多条轨迹明细则不允许修改
|
var trackById = tracks.FirstOrDefault(x => x.Id == @event.EsId);
|
||||||
var existTracks = tracks.Where(x => x.OrderId == order.OrderId
|
if (trackById != null)
|
||||||
&& x.TrackTime == @event.TrackTime).ToArray();
|
|
||||||
if (existTracks.Length > 1)
|
|
||||||
{
|
{
|
||||||
// 修改轨迹时,订单存在多条轨迹不允许修改
|
updateTracks.Add(BuiltUpdateTrack(@event, trackById, order, trackContent));
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
track = existTracks.FirstOrDefault();
|
var existTracks = tracks.Where(x => x.OrderId == order.OrderId).ToList();
|
||||||
|
|
||||||
if (track == null) continue; // 不存在不让改
|
if (@event.CompareFields.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
existTracks = existTracks.Where(x => x.TrackTime == @event.TrackTime).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 【批量新增】所有可能遇到的场景
|
Debug.Assert(@event.CompareFields != null, "@event.CompareFields != null");
|
||||||
// 标识:允许重复,不允许重复,零条,一条,多条;
|
var extraDict = TextJsonHelper.DeserializeToDictionary(@event.Extra);
|
||||||
// 场景A:允许重复,零条 => 新增
|
if (extraDict == null || !extraDict.TryGetValue(@event.CompareFields, out var compareValue))
|
||||||
// 场景B:允许重复,一条 => 新增(约束受限新增,否则跳过新增)
|
{
|
||||||
// 场景C:允许重复,多条 => 新增(约束受限新增,否则跳过新增)
|
throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{@event.CompareFields}");
|
||||||
// 场景D:不允许重复,零条 => 新增
|
}
|
||||||
// 场景E:不允许重复,一条 => 跳过
|
|
||||||
// 场景F:不允许重复,(理想不会出现多条) => 跳过
|
|
||||||
var existTracks = tracks.Where(x => x.OrderId == order.OrderId).ToArray();
|
|
||||||
track = existTracks.FirstOrDefault();
|
|
||||||
|
|
||||||
//覆盖场景:B,C
|
existTracks = existTracks.Where(x =>
|
||||||
if (trackContent.IsRepeatable && existTracks.Length >= 1)
|
|
||||||
{
|
{
|
||||||
if (existTracks.Any(x => x.TrackPlace == @event.TrackPlace && x.TrackTime == @event.TrackTime))
|
var oldExtraDict = TextJsonHelper.DeserializeToDictionary(x.Extra);
|
||||||
|
// tips:注意兼容性,历史轨迹的字段可能为空
|
||||||
|
if (oldExtraDict == null || !oldExtraDict.TryGetValue(@event.CompareFields, out var oldValue))
|
||||||
{
|
{
|
||||||
//允许重复,出现【轨迹发生地】,【轨迹发生时间】的都重复,则不允许新增
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextJsonHelper.EqJsonElement(oldValue, compareValue);
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var track = existTracks.FirstOrDefault();
|
||||||
|
|
||||||
|
if (!@event.IsAdd)
|
||||||
|
{
|
||||||
|
if (existTracks.Count > 1)
|
||||||
|
{
|
||||||
|
// todo: 所有的event handle 多写log,取缔注释,特别是continue,return,这种跳出的地方,方便排查问题
|
||||||
|
_logger.LogInformation("订单存在多条轨迹不允许修改:{@event}", @event);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置null后面执行新增逻辑
|
// todo:例如这里
|
||||||
track = null;
|
if (track == null) continue; // 不存在不让改
|
||||||
}
|
|
||||||
|
|
||||||
//不允许重复,并且记录大于等于一条,跳过
|
updateTracks.Add(BuiltUpdateTrack(@event, track, order, trackContent));
|
||||||
//覆盖场景:E,F
|
operationRecords.Add(BuildOrderOperationRecord(@event, track, order));
|
||||||
if (!trackContent.IsRepeatable && existTracks.Length >= 1)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
continue;
|
// 不允许重复轨迹,跳过
|
||||||
|
if (!trackContent.IsRepeatable && existTracks.Count > 0) continue;
|
||||||
|
|
||||||
|
insertTracks.Add(BuiltNewTrack(@event, order, trackContent));
|
||||||
}
|
}
|
||||||
|
|
||||||
//其余情况:A,D都为新增操作,无需检查数量,track为null执行新增操作
|
canNextOrderIds.Add(order.OrderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track == default)
|
if (updateTracks.Any())
|
||||||
{
|
{
|
||||||
track = new TrackDetailsIndex
|
//批量差异化更新轨迹
|
||||||
|
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,
|
SubSystemId = @event.SubSystemId,
|
||||||
OrderId = order.OrderId,
|
OrderId = order.OrderId,
|
||||||
@ -384,83 +428,33 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
|
|||||||
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
|
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
|
||||||
? track.TrackTime
|
? track.TrackTime
|
||||||
: track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
|
: track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone));
|
||||||
insertTracks.Add(track);
|
|
||||||
|
|
||||||
// 写入操作日志
|
return track;
|
||||||
_ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex
|
}
|
||||||
|
|
||||||
|
private OrderOperationRecordIndex BuildOrderOperationRecord(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order)
|
||||||
|
{
|
||||||
|
return new OrderOperationRecordIndex
|
||||||
{
|
{
|
||||||
OrderId = order.OrderId,
|
OrderId = order.OrderId,
|
||||||
OrderNo = order.OrderNo,
|
OrderNo = order.OrderNo,
|
||||||
OptionType = OrderOperationType.创建轨迹.ToString(),
|
OptionType = @event.IsAdd ? OrderOperationType.创建轨迹.ToString() : OrderOperationType.修改轨迹.ToString(),
|
||||||
Content = track.ToJson(),
|
Content = track.ToJson(),
|
||||||
CreateUserId = @event.OperationManId,
|
CreateUserId = @event.OperationManId,
|
||||||
CreateUserName = @event.OperationMan ?? "",
|
CreateUserName = @event.OperationMan ?? "",
|
||||||
CreateTime = DateTime.Now
|
CreateTime = DateTime.Now
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
private async Task EnsureWriteAfterPublicTopicAsync(TrackUpsertEvent @event, string subSystemCode, string statusCode)
|
||||||
{
|
{
|
||||||
//外部轨迹,轨迹发生地,轨迹发生时间,轨迹发生时区,不允许更改
|
//理想情况在写入之后1s会刷盘 https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html
|
||||||
if (track.Source != (int) TrackSourceEnum.ExternalServiceProvide)
|
//增加一个版本号来确定是否真的变更了
|
||||||
{
|
//没有刷盘成功事件回调
|
||||||
track.TrackPlace = @event.TrackPlace;
|
//方案1:!!【轮询等待静默刷盘】查出版本号确实发生了变更在发送广播
|
||||||
track.TrackTime = @event.NewTrackTime ?? @event.TrackTime;
|
//方案2:考虑强制刷盘(对es压力大)后发送
|
||||||
track.TrackTimeZone = @event.TrackTimeZone;
|
//方案3:采用一个较大延时,不查询直接发
|
||||||
}
|
await Task.Delay(1000);
|
||||||
|
_broadcastingService.TrackChangePublicTopic(@event, subSystemCode, statusCode);
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
canNextOrderIds.Add(order.OrderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateTracks.Any())
|
|
||||||
{
|
|
||||||
//批量差异化更新轨迹
|
|
||||||
await _trackDetailsEsRepository.BulkUpdateAsync(updateTracks);
|
|
||||||
}
|
|
||||||
|
|
||||||
return insertTracks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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>
|
/// </summary>
|
||||||
public string PushTrackInterfaceCode { get; set; }
|
public string PushTrackInterfaceCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 推送轨迹接口Id
|
||||||
|
/// </summary>
|
||||||
|
public int PushTrackInterfaceId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 推送轨迹接口 内容项 参数别名前缀
|
||||||
|
/// </summary>
|
||||||
|
public string PushTrackItemParamAliasPrefix { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新轨迹接口代码
|
/// 更新轨迹接口代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using RabbitMQ.Client.Events;
|
|||||||
using SJZY.Expand.ABP.Core.Logger;
|
using SJZY.Expand.ABP.Core.Logger;
|
||||||
using SJZY.InterfaceRelay.Application.Contracts;
|
using SJZY.InterfaceRelay.Application.Contracts;
|
||||||
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||||
|
using SJZY.Track.Application.Contract.Services;
|
||||||
using SJZY.Track.Application.Helpers;
|
using SJZY.Track.Application.Helpers;
|
||||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
|
||||||
@ -18,12 +19,15 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
|||||||
{
|
{
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
||||||
|
private readonly IBroadcastingService _broadcastingService;
|
||||||
|
|
||||||
public TrackPushCompletedEventHandler(IOrderRepository orderRepository,
|
public TrackPushCompletedEventHandler(IOrderRepository orderRepository,
|
||||||
ITrackPushRecordEsRepository trackPushRecordEsRepository)
|
ITrackPushRecordEsRepository trackPushRecordEsRepository,
|
||||||
|
IBroadcastingService broadcastingService)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_trackPushRecordEsRepository = trackPushRecordEsRepository;
|
_trackPushRecordEsRepository = trackPushRecordEsRepository;
|
||||||
|
_broadcastingService = broadcastingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConsumeOptions Options()
|
public ConsumeOptions Options()
|
||||||
@ -49,11 +53,11 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
|||||||
var optionType = Base64Helper.DeSerialize<string>(@event.Attach);
|
var optionType = Base64Helper.DeSerialize<string>(@event.Attach);
|
||||||
if (optionType == OptionType.新增.ToString())
|
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())
|
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();
|
if (logStr.IsNullOrEmpty()) throw new InvalidOperationException();
|
||||||
@ -64,6 +68,10 @@ public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandl
|
|||||||
log.Message = @event.Message;
|
log.Message = @event.Message;
|
||||||
log.RequestId = @event.RequestId;
|
log.RequestId = @event.RequestId;
|
||||||
|
|
||||||
|
// 推送广播
|
||||||
|
if (log.IsToMq)
|
||||||
|
_broadcastingService.TrackPushCompletedPublicTopic(BuildDto(log));
|
||||||
|
|
||||||
// 往es 写推送日志
|
// 往es 写推送日志
|
||||||
await _trackPushRecordEsRepository.AddAsync(log);
|
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="BSI.Stack.Rabbit" Version="2.1.3" />
|
||||||
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue" Version="8.2.1"/>
|
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue" Version="8.2.1"/>
|
||||||
<PackageReference Include="SJZY.Expand.AliyunOSS" Version="7.0.17" />
|
<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.Http.Client" Version="7.0.2" />
|
||||||
<PackageReference Include="Volo.Abp.FluentValidation" Version="7.0.2" />
|
<PackageReference Include="Volo.Abp.FluentValidation" Version="7.0.2" />
|
||||||
<PackageReference Include="SJZY.UserCenter.HttpApi" Version="3.1.8.17-alpha" />
|
<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.OrderFlights = ObjectMapper.Map<List<OrderFlightInfo>, List<OrderFlightEntity>>(input.FlightInfos);
|
||||||
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
|
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
|
||||||
order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(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);
|
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.OrderFlights = ObjectMapper.Map<List<OrderFlightInfo>, List<OrderFlightEntity>>(input.FlightInfos);
|
||||||
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
|
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
|
||||||
order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(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);
|
await _orderRepository.UpdateOrderAsync(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
using DotNetCore.CAP;
|
using DotNetCore.CAP;
|
||||||
|
using SJZY.Expand.ABP.Core.Common;
|
||||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||||
using SJZY.Track.Application.Contract.Dtos.TrackOrder;
|
using SJZY.Track.Application.Contract.Dtos.TrackOrder;
|
||||||
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
using SJZY.Track.Application.Contract.Dtos.TrackPush;
|
||||||
using SJZY.Track.Application.Contract.Events;
|
using SJZY.Track.Application.Contract.Events;
|
||||||
using SJZY.Track.Application.Contract.Services.ProvideServices;
|
using SJZY.Track.Application.Contract.Services.ProvideServices;
|
||||||
|
using SJZY.Track.Application.Helpers;
|
||||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||||
|
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
|
||||||
using SJZY.Track.Domain.Dtos.TrackPush;
|
using SJZY.Track.Domain.Dtos.TrackPush;
|
||||||
using SJZY.Track.Domain.Queries;
|
using SJZY.Track.Domain.Queries;
|
||||||
@ -26,12 +29,14 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
|||||||
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
||||||
private readonly ITrackPushConfigRepository _trackPushConfigRepository;
|
private readonly ITrackPushConfigRepository _trackPushConfigRepository;
|
||||||
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
|
||||||
|
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||||
|
|
||||||
public TrackPushService(IOrderRepository orderRepository
|
public TrackPushService(IOrderRepository orderRepository
|
||||||
, ICapPublisher capPublisher
|
, ICapPublisher capPublisher
|
||||||
, ITrackPushRecordEsRepository trackPushRecordEsRepository
|
, ITrackPushRecordEsRepository trackPushRecordEsRepository
|
||||||
, IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService
|
, IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService
|
||||||
, ITrackPushConfigRepository trackPushConfigRepository, IProvideQueries provideQueries)
|
, ITrackPushConfigRepository trackPushConfigRepository, IProvideQueries provideQueries,
|
||||||
|
ITrackDetailsEsRepository trackDetailsEsRepository)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_capPublisher = capPublisher;
|
_capPublisher = capPublisher;
|
||||||
@ -39,6 +44,7 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
|||||||
_requestCurrentUserService = requestCurrentUserService;
|
_requestCurrentUserService = requestCurrentUserService;
|
||||||
_trackPushConfigRepository = trackPushConfigRepository;
|
_trackPushConfigRepository = trackPushConfigRepository;
|
||||||
_provideQueries = provideQueries;
|
_provideQueries = provideQueries;
|
||||||
|
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -47,7 +53,8 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
|||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("Track/Push")]
|
[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(); // 单号去重、去空
|
input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空
|
||||||
|
|
||||||
@ -74,23 +81,92 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
|||||||
|
|
||||||
var name = userInfo.Data.UserName;
|
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
|
var trackPushEvent = new TrackPushEvent
|
||||||
{
|
{
|
||||||
OptionType = OptionType.新增,
|
OptionType = OptionType.新增,
|
||||||
SubSystemId = input.SubSystemId,
|
SubSystemId = input.SubSystemId,
|
||||||
SubSystemCode = subSystemCode,
|
SubSystemCode = subSystemCode,
|
||||||
CustomId = group.Key,
|
CustomId = order.CustomId,
|
||||||
OrderIds = group.Select(x => x.Id).ToArray(),
|
OrderIds = new[] { order.Id },
|
||||||
TrackCode = input.TrackCode,
|
TrackCode = input.TrackCode,
|
||||||
OperationMan = name,
|
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);
|
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>
|
/// <param name="customerId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet("Track/GetTrackPushContentList")]
|
[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 list = await _trackPushConfigRepository.GetTrackPushContentListAsync(subSystemId, customerId);
|
||||||
|
|
||||||
var result = ObjectMapper.Map<List<GetTrackPushContentListVo>, List<TrackPushContentDto>>(list);
|
var result = ObjectMapper.Map<List<GetTrackPushContentListVo>, List<TrackPushContentDto>>(list);
|
||||||
|
|
||||||
return result;
|
return new UnifyResultDto<List<TrackPushContentDto>>(true, result, "操作成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -116,7 +193,8 @@ public class TrackPushService : ApplicationService, ITrackPushService
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
[HttpGet("Track/GetTrackPushRecords")]
|
[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 =>
|
var orderId = await _orderRepository.GetFirstAsync(x =>
|
||||||
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && input.OrderNo == x.OrderNo,
|
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);
|
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.Application.Contract.Dtos.ProvideServices;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
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;
|
namespace SJZY.Track.Application.Services.ProvideServices;
|
||||||
|
|
||||||
@ -9,9 +13,12 @@ namespace SJZY.Track.Application.Services.ProvideServices;
|
|||||||
public partial class TrackService
|
public partial class TrackService
|
||||||
{
|
{
|
||||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||||
|
private readonly ITrackTemplateRepository _trackTemplateRepository;
|
||||||
|
private readonly IHttpContextAccessor _contextAccessor;
|
||||||
|
private readonly IVSystemQueries _vSystemQueries;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询轨迹
|
/// 查询轨迹(时区补正)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@ -24,9 +31,12 @@ public partial class TrackService
|
|||||||
|
|
||||||
var details = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos);
|
var details = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos);
|
||||||
|
|
||||||
|
//内部子系统不过滤外部轨迹
|
||||||
|
var isFilterExternal = await HasFilterExternalTrack();
|
||||||
|
|
||||||
// 是否对外
|
// 是否对外
|
||||||
var trackCodes = details.Select(x => x.TrackCode)
|
var trackCodes = details.Select(x => x.TrackCode)
|
||||||
.Where(x => x != GlobalConst.EmptyString)
|
.WhereIf(isFilterExternal, x => x != GlobalConst.EmptyString)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -51,6 +61,7 @@ public partial class TrackService
|
|||||||
|
|
||||||
item.TrackDetails = trackDetails.Select(x => new TrackDetail
|
item.TrackDetails = trackDetails.Select(x => new TrackDetail
|
||||||
{
|
{
|
||||||
|
EsId = x.Id,
|
||||||
Code = x.TrackCode,
|
Code = x.TrackCode,
|
||||||
Status = x.TrackStatus,
|
Status = x.TrackStatus,
|
||||||
Content = x.TrackContent,
|
Content = x.TrackContent,
|
||||||
@ -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.ByTrackTime:
|
||||||
|
case SortMethod.ByTemplateAndTrackTime:
|
||||||
// tips:quick-sort 直接修改原list
|
// tips:quick-sort 直接修改原list
|
||||||
list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time)));
|
list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time)));
|
||||||
break;
|
break;
|
||||||
case null:
|
case null:
|
||||||
case SortMethod.ByTrackTimeDesc:
|
case SortMethod.ByTrackTimeDesc:
|
||||||
|
case SortMethod.ByTemplateAndTrackTimeDesc:
|
||||||
list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time)));
|
list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time)));
|
||||||
break;
|
break;
|
||||||
default:
|
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 DotNetCore.CAP;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||||
using SJZY.Track.Application.Contract.Events;
|
using SJZY.Track.Application.Contract.Events;
|
||||||
using SJZY.Track.Application.Contract.Services.ProvideServices;
|
using SJZY.Track.Application.Contract.Services.ProvideServices;
|
||||||
|
using SJZY.Track.Application.Helpers;
|
||||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||||
|
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
|
||||||
using SJZY.Track.Domain.Enums;
|
using SJZY.Track.Domain.Enums;
|
||||||
|
using SJZY.Track.Domain.Queries;
|
||||||
using SJZY.UserCenter.HttpApi.Services;
|
using SJZY.UserCenter.HttpApi.Services;
|
||||||
using SJZY.UserCenter.HttpApi.Services.User;
|
using SJZY.UserCenter.HttpApi.Services.User;
|
||||||
using Volo.Abp.Http.Client.DynamicProxying;
|
using Volo.Abp.Http.Client.DynamicProxying;
|
||||||
@ -24,149 +28,25 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
||||||
private readonly ITrackContentRepository _trackContentRepository;
|
private readonly ITrackContentRepository _trackContentRepository;
|
||||||
|
|
||||||
public TrackService(IOrderRepository orderRepository, ICapPublisher capPublisher,
|
public TrackService(IOrderRepository orderRepository,
|
||||||
ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository,
|
ICapPublisher capPublisher,
|
||||||
IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService)
|
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||||
|
ITrackContentRepository trackContentRepository,
|
||||||
|
IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService,
|
||||||
|
ITrackTemplateRepository trackTemplateRepository,
|
||||||
|
IHttpContextAccessor contextAccessor,
|
||||||
|
IVSystemQueries vSystemQueries)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_capPublisher = capPublisher;
|
_capPublisher = capPublisher;
|
||||||
_trackContentRepository = trackContentRepository;
|
_trackContentRepository = trackContentRepository;
|
||||||
_requestCurrentUserService = requestCurrentUserService;
|
_requestCurrentUserService = requestCurrentUserService;
|
||||||
|
_vSystemQueries = vSystemQueries;
|
||||||
|
_contextAccessor = contextAccessor;
|
||||||
|
_trackTemplateRepository = trackTemplateRepository;
|
||||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
_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>
|
||||||
/// 删除轨迹
|
/// 删除轨迹
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -193,29 +73,69 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
|
|
||||||
var name = userInfo.Data.UserName;
|
var name = userInfo.Data.UserName;
|
||||||
|
|
||||||
//删除轨迹约束,只要其中有一条来源是外部的就立即返回错误
|
var tracks = new List<TrackDetailsIndex>();
|
||||||
var tracks = await _trackDetailsEsRepository
|
var existsExternal = false;
|
||||||
.GetListAsync(new[] { orderId },
|
var esIds = input.EsIds?.Distinct().ToArray();
|
||||||
input.TrackIdentifiers.Select(x => x.TrackCode).ToList(),
|
//优先使用esId
|
||||||
TrackSourceEnum.ExternalServiceProvide);
|
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}")
|
tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCodes);
|
||||||
.Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList();
|
//检查删除的轨迹中是否包含外部轨迹
|
||||||
if (intersect.Count > 0)
|
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: "存在来源于外部服务商的轨迹,不允许删除");
|
throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除轨迹
|
if (tracks.Count == 0)
|
||||||
var @event = new TrackDeleteEvent
|
|
||||||
{
|
{
|
||||||
|
throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除轨迹
|
||||||
|
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe,
|
||||||
|
new TrackDeleteEvent
|
||||||
|
{
|
||||||
|
EsIds = input.EsIds?.ToArray(),
|
||||||
OrderIds = new[] { orderId },
|
OrderIds = new[] { orderId },
|
||||||
|
CompareFields = input.CompareFields,
|
||||||
|
CompareValue = input.CompareValue,
|
||||||
TrackIdentifiers = input.TrackIdentifiers,
|
TrackIdentifiers = input.TrackIdentifiers,
|
||||||
SubSystemId = input.SubSystemId,
|
SubSystemId = input.SubSystemId,
|
||||||
OperationMan = name
|
OperationMan = name
|
||||||
};
|
});
|
||||||
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event);
|
|
||||||
|
|
||||||
return new UnifyResultDto(true, true);
|
return new UnifyResultDto(true, true);
|
||||||
}
|
}
|
||||||
@ -297,7 +217,21 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
TrackSourceEnum.ExternalServiceProvide);
|
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();
|
.Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList();
|
||||||
if (intersect.Count > 0)
|
if (intersect.Count > 0)
|
||||||
{
|
{
|
||||||
@ -309,6 +243,8 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
{
|
{
|
||||||
OrderIds = orderIds.ToArray(),
|
OrderIds = orderIds.ToArray(),
|
||||||
TrackIdentifiers = input.TrackIdentifiers,
|
TrackIdentifiers = input.TrackIdentifiers,
|
||||||
|
CompareFields = input.CompareFields,
|
||||||
|
CompareValue = input.CompareValue,
|
||||||
SubSystemId = input.SubSystemId,
|
SubSystemId = input.SubSystemId,
|
||||||
OperationMan = userInfo.Data.UserName,
|
OperationMan = userInfo.Data.UserName,
|
||||||
};
|
};
|
||||||
@ -317,6 +253,76 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
return new UnifyResultDto(true, true);
|
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>
|
||||||
/// 批量新增、更新轨迹
|
/// 批量新增、更新轨迹
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -328,8 +334,9 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
{
|
{
|
||||||
input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空
|
input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空
|
||||||
var orders = await _orderRepository.GetListAsync(x =>
|
var orders = await _orderRepository.GetListAsync(x =>
|
||||||
x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType &&
|
x.SubSystemId == input.SubSystemId
|
||||||
input.OrderNos.Contains(x.OrderNo),
|
&& x.OrderType == input.OrderType
|
||||||
|
&& input.OrderNos.Contains(x.OrderNo),
|
||||||
x => new
|
x => new
|
||||||
{
|
{
|
||||||
x.Id,
|
x.Id,
|
||||||
@ -342,93 +349,26 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
throw new BusinessException(message: "订单一个都不存在");
|
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();
|
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))
|
// 更新轨迹时是否可以匹配到轨迹的检查
|
||||||
{
|
await TrackUpsertValidation(input.IsAdd,
|
||||||
throw new BusinessException(message: "轨迹时间不合法");
|
input.SubSystemId,
|
||||||
}
|
order.Id,
|
||||||
|
order.OrderNo,
|
||||||
if ((input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue) ||
|
input.TrackCode,
|
||||||
(input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false))
|
input.Source,
|
||||||
{
|
input.TrackTime,
|
||||||
throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入");
|
input.NewTrackTime,
|
||||||
}
|
input.EstimatedDeliveryDate,
|
||||||
|
input.DestinationTimeZone,
|
||||||
var trackContent = await _trackContentRepository.GetByCodeAsync(input.SubSystemId, input.TrackCode);
|
input.Extra,
|
||||||
if (trackContent == default)
|
input.CompareFields);
|
||||||
{
|
|
||||||
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}存在多条记录,不允许修改");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取用户name
|
// 获取用户name
|
||||||
var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync();
|
var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync();
|
||||||
@ -473,11 +413,168 @@ public partial class TrackService : ApplicationService, ITrackService
|
|||||||
TrackPlacePostcode = input.TrackPlacePostcode,
|
TrackPlacePostcode = input.TrackPlacePostcode,
|
||||||
EstimatedDeliveryDate = input.EstimatedDeliveryDate,
|
EstimatedDeliveryDate = input.EstimatedDeliveryDate,
|
||||||
DestinationTimeZone = input.DestinationTimeZone,
|
DestinationTimeZone = input.DestinationTimeZone,
|
||||||
Extra = input.Extra
|
CompareFields = input.CompareFields,
|
||||||
|
Extra = input.Extra,
|
||||||
|
ForcedPush = input.ForcedPush,
|
||||||
|
IsToMq = input.IsToMq,
|
||||||
};
|
};
|
||||||
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
|
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UnifyResultDto(true, true);
|
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.Expand.AliyunOSS;
|
||||||
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
|
||||||
using SJZY.Track.Application.Contract.Dtos.TrackContents;
|
using SJZY.Track.Application.Contract.Dtos.TrackContents;
|
||||||
|
using SJZY.Track.Application.Contract.Services;
|
||||||
using SJZY.Track.Application.Localization;
|
using SJZY.Track.Application.Localization;
|
||||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
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.TrackStatusAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
|
||||||
using SJZY.Track.Domain.Dtos.TrackContents;
|
using SJZY.Track.Domain.Dtos.TrackContents;
|
||||||
using SJZY.Track.Domain.Dtos.TrackTemplate;
|
using SJZY.Track.Domain.Enums;
|
||||||
using SJZY.Track.Domain.Queries;
|
using SJZY.Track.Domain.Queries;
|
||||||
|
|
||||||
namespace SJZY.Track.Application.Services.TrackContents;
|
namespace SJZY.Track.Application.Services.TrackContents;
|
||||||
@ -32,6 +33,7 @@ public class TrackContentService : ApplicationService
|
|||||||
private readonly IBasicQuery<TrackStatusEntity> _trackStatusBasicQuery;
|
private readonly IBasicQuery<TrackStatusEntity> _trackStatusBasicQuery;
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
|
||||||
|
private readonly ITrackPushCacheService _trackPushCacheService;
|
||||||
|
|
||||||
public TrackContentService(
|
public TrackContentService(
|
||||||
IStringLocalizer<TrackLocalizationResource> stringLocalizer,
|
IStringLocalizer<TrackLocalizationResource> stringLocalizer,
|
||||||
@ -40,7 +42,7 @@ public class TrackContentService : ApplicationService
|
|||||||
IBasicQuery<TrackFlagEntity> trackFlagBasicQuery,
|
IBasicQuery<TrackFlagEntity> trackFlagBasicQuery,
|
||||||
IOrderRepository orderRepository,
|
IOrderRepository orderRepository,
|
||||||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||||||
ITrackTemplateRepository trackTemplateRepository)
|
ITrackTemplateRepository trackTemplateRepository, ITrackPushCacheService trackPushCacheService)
|
||||||
{
|
{
|
||||||
_stringLocalizer = stringLocalizer;
|
_stringLocalizer = stringLocalizer;
|
||||||
_trackContentRepository = trackContentRepository;
|
_trackContentRepository = trackContentRepository;
|
||||||
@ -49,6 +51,7 @@ public class TrackContentService : ApplicationService
|
|||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||||||
_trackTemplateRepository = trackTemplateRepository;
|
_trackTemplateRepository = trackTemplateRepository;
|
||||||
|
_trackPushCacheService = trackPushCacheService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -289,9 +292,40 @@ public class TrackContentService : ApplicationService
|
|||||||
if (order == default)
|
if (order == default)
|
||||||
throw new BusinessException(message: "订单不存在!");
|
throw new BusinessException(message: "订单不存在!");
|
||||||
|
|
||||||
|
var res = new UnifyResultDto<List<GetAvailableContentOutput>>(true)
|
||||||
|
{
|
||||||
|
Data = new List<GetAvailableContentOutput>()
|
||||||
|
};
|
||||||
|
|
||||||
//获取轨迹详情
|
//获取轨迹详情
|
||||||
var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id);
|
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);
|
var contentList = await _trackContentRepository.GetListBySystemIdAsync(input.SystemId);
|
||||||
if (contentList == null)
|
if (contentList == null)
|
||||||
@ -305,11 +339,6 @@ public class TrackContentService : ApplicationService
|
|||||||
contentList = contentList.Where(m => template.Contains(m.Code)).ToList();
|
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)
|
foreach (var item in contentList)
|
||||||
{
|
{
|
||||||
//新增时跳过已存在轨迹内容
|
//新增时跳过已存在轨迹内容
|
||||||
@ -344,7 +373,7 @@ public class TrackContentService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//修改操作,查轨迹内容列表反映明细表数据,重新构造响应数据
|
//修改/删除/推送 操作,查轨迹内容列表反映明细表数据,重新构造响应数据
|
||||||
var matchContent = new List<GetAvailableContentOutput>();
|
var matchContent = new List<GetAvailableContentOutput>();
|
||||||
var contents = res.Data.Select(x => new
|
var contents = res.Data.Select(x => new
|
||||||
{
|
{
|
||||||
|
|||||||
@ -51,6 +51,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
|
|||||||
x.Id,
|
x.Id,
|
||||||
x.IsAutoPush,
|
x.IsAutoPush,
|
||||||
x.IsAllPush,
|
x.IsAllPush,
|
||||||
|
x.IsAllPushWithLatest,
|
||||||
x.IsCanDelete,
|
x.IsCanDelete,
|
||||||
x.IsCanUpdate,
|
x.IsCanUpdate,
|
||||||
x.SubSystemId,
|
x.SubSystemId,
|
||||||
@ -76,6 +77,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
|
|||||||
IsAutoPush = trackPushConfig.IsAutoPush,
|
IsAutoPush = trackPushConfig.IsAutoPush,
|
||||||
IsCanUpdate = trackPushConfig.IsCanUpdate,
|
IsCanUpdate = trackPushConfig.IsCanUpdate,
|
||||||
IsAllPush = trackPushConfig.IsAllPush,
|
IsAllPush = trackPushConfig.IsAllPush,
|
||||||
|
IsAllPushWithLatest = trackPushConfig.IsAllPushWithLatest,
|
||||||
IsCanDelete = trackPushConfig.IsCanDelete,
|
IsCanDelete = trackPushConfig.IsCanDelete,
|
||||||
DateTimeFormatType = (int) trackPushConfig.DateTimeFormatType,
|
DateTimeFormatType = (int) trackPushConfig.DateTimeFormatType,
|
||||||
DateTimeFormat = trackPushConfig.DateTimeFormat,
|
DateTimeFormat = trackPushConfig.DateTimeFormat,
|
||||||
@ -89,6 +91,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
|
|||||||
TrackContentValue = item.TrackContentValue,
|
TrackContentValue = item.TrackContentValue,
|
||||||
TrackEnContentValue = item.TrackEnContentValue,
|
TrackEnContentValue = item.TrackEnContentValue,
|
||||||
TrackTimeZone = item.TrackTimeZone,
|
TrackTimeZone = item.TrackTimeZone,
|
||||||
|
// todo:废弃字段如果没有外部子系统依赖,可以逐步删除
|
||||||
ExpandFieldsValue = item.ExpandFieldsValue,
|
ExpandFieldsValue = item.ExpandFieldsValue,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
|
|||||||
@ -143,6 +143,7 @@ public class SjzyTrackApplicationModule : AbpModule
|
|||||||
options.Declarations = new List<Action<IDeclaration>>()
|
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>
|
options.Consumes = new List<ConsumeOptions>
|
||||||
{
|
{
|
||||||
@ -158,6 +159,19 @@ public class SjzyTrackApplicationModule : AbpModule
|
|||||||
o.QueueBind(GlobalConst.TrackRefreshSubscribe, GlobalConst.InterfaceRelayExchange,
|
o.QueueBind(GlobalConst.TrackRefreshSubscribe, GlobalConst.InterfaceRelayExchange,
|
||||||
GlobalConst.TrackRefreshSubscribe);
|
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);
|
}, typeof(SjzyTrackApplicationModule).Assembly);
|
||||||
|
|||||||
@ -9,6 +9,21 @@ public interface IOrderOperationRecordEsRepository
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task AddAsync(OrderOperationRecordIndex index);
|
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>
|
||||||
/// 获取订单操作记录
|
/// 获取订单操作记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -62,6 +62,27 @@ public interface IOrderRepository : IBasicRepository<OrderEntity>
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<(string code, int id)>> GetSubSystemListByCodesAsync(List<string> codes);
|
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 订单关联
|
#region 订单关联
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -10,7 +10,7 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
|
|||||||
|
|
||||||
Task<List<TrackDetailsIndex>> GetLatestListAsync(int[] eventOrderIds, List<string> trackCodes);
|
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);
|
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<List<int>> DeleteTrackAsync(int[] orderIds, List<string> trackCodes);
|
||||||
|
|
||||||
Task DeleteTrackByIdAsync(string id, string indexName);
|
Task DeleteTrackByIdAsync(string id, string indexName);
|
||||||
|
|
||||||
Task<List<TrackDetailsIndex>> GetDataByIds(string[] ids);
|
Task<List<TrackDetailsIndex>> GetDataByIds(string[] ids);
|
||||||
|
|
||||||
Task<TrackDetailsIndex> GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime);
|
Task<TrackDetailsIndex> GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -190,5 +190,5 @@ public class TrackDetailsIndex : IdBaseIndex
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 扩展信息字段,用与轨迹推送的附加字段
|
/// 扩展信息字段,用与轨迹推送的附加字段
|
||||||
/// </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);
|
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>
|
||||||
/// 获取轨迹推送记录
|
/// 获取轨迹推送记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -22,6 +30,14 @@ public interface ITrackPushRecordEsRepository
|
|||||||
/// 获取最新轨迹推送记录
|
/// 获取最新轨迹推送记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="orderId"></param>
|
/// <param name="orderId"></param>
|
||||||
|
/// <param name="isSuccess">只选择成功的记录</param>
|
||||||
/// <returns></returns>
|
/// <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")]
|
[SugarColumn(ColumnName = "IsAllPush")]
|
||||||
public bool IsAllPush { get; set; }
|
public bool IsAllPush { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否全量推送(最新轨迹)
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "IsAllPushWithLatest")]
|
||||||
|
public bool IsAllPushWithLatest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 日期时间格式类型
|
/// 日期时间格式类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -82,4 +82,19 @@ public class TrackPushRecordIndex : IdBaseIndex
|
|||||||
|
|
||||||
/// <summary>创建时间</summary>
|
/// <summary>创建时间</summary>
|
||||||
public DateTime CreateTime { get; set; }
|
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);
|
Expression<Func<TrackTemplateContentEntity, bool>> whereExpression);
|
||||||
|
|
||||||
Task<List<TrackTemplateOutputVo>> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input);
|
Task<List<TrackTemplateOutputVo>> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input);
|
||||||
|
|
||||||
Task<UnifyPageResultDto<TemplateContentDtoVo>> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input);
|
Task<UnifyPageResultDto<TemplateContentDtoVo>> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input);
|
||||||
|
|
||||||
Task<List<string>> GetContentByTemplateCodes(string[] codes, int systemId);
|
Task<List<string>> GetContentByTemplateCodes(string[] codes, int systemId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,5 +57,8 @@ public partial class GlobalConst
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string TrackChangeExchange = "sjzy.track.on_track_change_ex";
|
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_OrderType = "TrackOrderType";
|
||||||
public const string MainDataKey_TrackQuestionType = "TrackQuestionType";
|
public const string MainDataKey_TrackQuestionType = "TrackQuestionType";
|
||||||
|
public const string HTTP_HEADER_SUBSYSTEMID = "Subsystemid";
|
||||||
public const string SystemUser = "系统";
|
public const string SystemUser = "系统";
|
||||||
public const string EmptyString = "--";
|
public const string EmptyString = "--";
|
||||||
public const int ChunkSize = 100;
|
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
|
public class TrackContentVO
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 子系统Id
|
||||||
|
/// </summary>
|
||||||
|
public int SubSystemId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 子系统代码
|
/// 子系统代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -51,6 +51,11 @@ public class GetTrackPushConfigDetailOutputVO
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAllPush { get; set; }
|
public bool IsAllPush { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否全量推送(最新轨迹)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAllPushWithLatest { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 时间格式枚举
|
/// 时间格式枚举
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -54,4 +54,9 @@ public class TemplateContentDtoVo
|
|||||||
/// 轨迹节点
|
/// 轨迹节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Node { get; set; }
|
public string Node { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序键
|
||||||
|
/// </summary>
|
||||||
|
public int Sort { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,17 +8,17 @@ namespace SJZY.Track.Domain.Enums;
|
|||||||
public enum TrackSourceEnum
|
public enum TrackSourceEnum
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 外部服务商创建
|
/// 外部服务商
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("外部服务商创建")] ExternalServiceProvide = 1,
|
[Description("外部服务商")] ExternalServiceProvide = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部系统创建
|
/// 内部系统
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("内部系统创建")] InternalService = 2,
|
[Description("内部系统")] InternalService = 2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 人工创建
|
/// 人工
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("人工创建")] Artificial = 3,
|
[Description("人工")] Artificial = 3,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,14 @@ public interface IProvideQueries
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<TrackContentVO?> GetTrackContentAsync(int subSystemId, string trackCode);
|
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>
|
||||||
/// 获取所有拉取配置
|
/// 获取所有拉取配置
|
||||||
/// </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>
|
/// </summary>
|
||||||
[SugarTable("v_system")]
|
[SugarTable("v_system")]
|
||||||
public class VSystemEntity : IFullAuditedBasicEntitys
|
public class VSystemEntity : IFullAuditedBasicEntitys, IEntity
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 子系统id
|
/// 子系统id
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
|
||||||
|
using SJZY.Track.Domain.Aggregates.TrackFlagAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackPullAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackPullAggregate;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
|
||||||
using SJZY.Track.Domain.Dtos.Order;
|
using SJZY.Track.Domain.Dtos.Order;
|
||||||
@ -99,24 +100,52 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, ITransientDepen
|
|||||||
return await Context.Queryable<TrackContentEntity>()
|
return await Context.Queryable<TrackContentEntity>()
|
||||||
.LeftJoin<TrackStatusEntity>((x, y) => x.TrackStatusId == y.Id)
|
.LeftJoin<TrackStatusEntity>((x, y) => x.TrackStatusId == y.Id)
|
||||||
.LeftJoin<VSystemEntity>((x, y, z) => x.SubSystemId == z.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)
|
.Where(x => x.SubSystemId == subSystemId && x.Code == trackCode)
|
||||||
.Select((x, y, z) => new TrackContentVO
|
.Select((x, y, z, k) => new TrackContentVO
|
||||||
{
|
{
|
||||||
SubSystemCode = z.Key,
|
SubSystemCode = z.Key,
|
||||||
TrackStatusId = x.TrackStatusId,
|
TrackStatusId = x.TrackStatusId,
|
||||||
TrackStatus = y.Status,
|
TrackStatus = y.Status,
|
||||||
TrackStatusCode = y.Code,
|
TrackStatusCode = y.Code,
|
||||||
|
TrackContentCode = x.Code,
|
||||||
TrackContent = x.Content,
|
TrackContent = x.Content,
|
||||||
TrackEnContent = x.EnContent,
|
TrackEnContent = x.EnContent,
|
||||||
IsCompleted = y.IsCompleted,
|
IsCompleted = y.IsCompleted,
|
||||||
IsRepeatable = x.IsRepeatable,
|
IsRepeatable = x.IsRepeatable,
|
||||||
IsAllowManuallyUpdate = x.IsAllowManuallyUpdate,
|
IsAllowManuallyUpdate = x.IsAllowManuallyUpdate,
|
||||||
IsAllowManuallyCreate = x.IsAllowManuallyCreate,
|
IsAllowManuallyCreate = x.IsAllowManuallyCreate,
|
||||||
IsToMq = y.IsToMq,
|
IsToMq = y.IsToMq || k.IsToMq,
|
||||||
})
|
})
|
||||||
.FirstAsync();
|
.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()
|
public async Task<List<TrackPullConfigVo>> GetAllPullConfigsAsync()
|
||||||
{
|
{
|
||||||
return await Context.Queryable<TrackPullConfigEntity>()
|
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)
|
public async Task<List<OrderOperationRecordIndex>> GetOrderOperationsByIdAsync(int orderId)
|
||||||
{
|
{
|
||||||
var data = await Context.SearchAsync<OrderOperationRecordIndex>(x => x
|
var data = await Context.SearchAsync<OrderOperationRecordIndex>(x => x
|
||||||
@ -39,6 +69,6 @@ public class OrderOperationRecordEsRepository : ElasticSearchContextAbstract<Ord
|
|||||||
.Size(GlobalConst.NormalLimit)
|
.Size(GlobalConst.NormalLimit)
|
||||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
.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.Expand.ABP.Core.Logger;
|
||||||
using SJZY.Track.Domain;
|
using SJZY.Track.Domain;
|
||||||
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
using SJZY.Track.Domain.Aggregates.OrderAggregate;
|
||||||
@ -11,16 +11,178 @@ namespace SJZY.Track.Repository.Repositories;
|
|||||||
|
|
||||||
public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, ITransientDependency
|
public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, ITransientDependency
|
||||||
{
|
{
|
||||||
|
//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)
|
||||||
|
{
|
||||||
|
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<OrderPlatformNumberEntity>((a, b) => a.Id == b.OrderId && b.IsDeleted == false)
|
||||||
|
.Where((a, b) => orderIds.Contains(a.Id))
|
||||||
|
.Select(a => new OrderEntity()
|
||||||
|
{
|
||||||
|
Id = a.Id,
|
||||||
|
OrderPlatformNumbers = a.OrderPlatformNumbers
|
||||||
|
})
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//从主数据中心查询类型描述
|
||||||
|
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))
|
||||||
|
)
|
||||||
|
.Select(x => new
|
||||||
|
{
|
||||||
|
x.Property,
|
||||||
|
x.Enumkey,
|
||||||
|
x.Disp
|
||||||
|
})
|
||||||
|
.ToListAsync()
|
||||||
|
)
|
||||||
|
.GroupBy(x => x.Property)
|
||||||
|
.ToDictionary(
|
||||||
|
g => g.Key,
|
||||||
|
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)
|
public async Task<UnifyPageResultDto<TrackOrderVO>> GetTrackOrderPagedList(GetPageTrackOrderInputVO input)
|
||||||
{
|
{
|
||||||
//查询完去重
|
//查询完去重
|
||||||
var pageList = await Context.Queryable<OrderEntity>()
|
UnifyPageResultDto<TrackOrderVO> pageList;
|
||||||
.Includes(a => a.OrderPlatformNumbers)
|
//没传递单号时
|
||||||
|
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<VExternalSubjectEntity>((a, b) => a.CustomId == b.Id && b.IsDeleted == false)
|
||||||
.LeftJoin<VSystemEntity>((a, b, c) => a.SubSystemId == c.Id && c.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.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,
|
.WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue,
|
||||||
(a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd)
|
(a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd)
|
||||||
.WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue),
|
.WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue),
|
||||||
@ -32,7 +194,6 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
|
|||||||
.WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType)
|
.WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType)
|
||||||
.WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted)
|
.WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted)
|
||||||
.OrderByDescending((a, b, c) => a.CreateTime)
|
.OrderByDescending((a, b, c) => a.CreateTime)
|
||||||
.Distinct()
|
|
||||||
.Select((a, b, c) => new TrackOrderVO
|
.Select((a, b, c) => new TrackOrderVO
|
||||||
{
|
{
|
||||||
Id = a.Id,
|
Id = a.Id,
|
||||||
@ -52,47 +213,35 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
|
|||||||
SubSystemId = c.Id,
|
SubSystemId = c.Id,
|
||||||
DestinationTimeZone = a.DestinationTimeZone,
|
DestinationTimeZone = a.DestinationTimeZone,
|
||||||
EstimatedDeliveryDate = a.EstimatedDeliveryDate,
|
EstimatedDeliveryDate = a.EstimatedDeliveryDate,
|
||||||
ThirdPartyOrderNumber = BuildThirdPartyOrderNumber(a.OrderPlatformNumbers)
|
|
||||||
})
|
})
|
||||||
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
.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 orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList();
|
||||||
var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList();
|
var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList();
|
||||||
//从主数据中心查询类型描述
|
var typeDisplayDict = await GetMainDataEnumForCacheAsync(orderTypes, questTypes);
|
||||||
var typeDispDict = (await Context.Queryable<VEnumValueInfoEntity>()
|
|
||||||
.Where(x =>
|
|
||||||
(x.Property == GlobalConst.MainDataKey_OrderType && orderTypes.Contains(x.Enumkey))
|
|
||||||
|| (x.Property == GlobalConst.MainDataKey_TrackQuestionType && questTypes.Contains(x.Enumkey))
|
|
||||||
)
|
|
||||||
.Select(x => new
|
|
||||||
{
|
|
||||||
x.Property,
|
|
||||||
x.Enumkey,
|
|
||||||
x.Disp
|
|
||||||
})
|
|
||||||
.ToListAsync()
|
|
||||||
)
|
|
||||||
.GroupBy(x => x.Property)
|
|
||||||
.ToDictionary(
|
|
||||||
g => g.Key,
|
|
||||||
y => y.ToDictionary(x => x.Enumkey, x => x.Disp)
|
|
||||||
);
|
|
||||||
|
|
||||||
//填充数描述信息
|
//填充数描述信息
|
||||||
pageList.List.ForEach(x =>
|
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)
|
? orderTypeDisplayDict.TryGetValue(x.OrderType, out var orderTypeDisplay)
|
||||||
? 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)
|
? questDisplayDict.TryGetValue(x.QuestionType, out var questDisplay)
|
||||||
? questDisplay
|
? questDisplay
|
||||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]"
|
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]"
|
||||||
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}]";
|
: $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}] EnumKey:[{x.OrderType}]";
|
||||||
});
|
});
|
||||||
|
|
||||||
return pageList;
|
return pageList;
|
||||||
@ -247,6 +396,32 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
|
|||||||
return res.Select(x => (x.Key, x.Id)).ToList();
|
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)
|
public Task<VSystemEntity> GetSystemInfoById(int id)
|
||||||
{
|
{
|
||||||
return Context.Queryable<VSystemEntity>().FirstAsync(m => m.IsDeleted == false && m.Id == 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>
|
/// </summary>
|
||||||
/// <param name="orderPlatformNumberEntities"></param>
|
/// <param name="orderPlatformNumberEntities"></param>
|
||||||
/// <returns></returns>
|
/// <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 = "、";
|
const string separator = "、";
|
||||||
var thirdPartyOrderNumbers = orderPlatformNumberEntities
|
var thirdPartyOrderNumbers = orderPlatformNumberEntities
|
||||||
.Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber))
|
.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);
|
return string.Join(separator, thirdPartyOrderNumbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ using SJZY.Expand.ABP.Core.PublicMethords;
|
|||||||
using SJZY.Expand.ElasticSearch.Services;
|
using SJZY.Expand.ElasticSearch.Services;
|
||||||
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
|
||||||
using SJZY.Track.Domain.Consts;
|
using SJZY.Track.Domain.Consts;
|
||||||
using SJZY.Track.Domain.Dtos.TrackContents;
|
|
||||||
using SJZY.Track.Domain.Enums;
|
using SJZY.Track.Domain.Enums;
|
||||||
|
|
||||||
namespace SJZY.Track.Repository.Repositories;
|
namespace SJZY.Track.Repository.Repositories;
|
||||||
@ -20,7 +19,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
|||||||
public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode,
|
public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode,
|
||||||
bool forUpsert = false)
|
bool forUpsert = false)
|
||||||
{
|
{
|
||||||
var r = !forUpsert
|
var r = forUpsert
|
||||||
? await Context.SearchAsync<TrackDetailsIndex>(s => s
|
? await Context.SearchAsync<TrackDetailsIndex>(s => s
|
||||||
.Index(GlobalConst.TrackDetailsIndex)
|
.Index(GlobalConst.TrackDetailsIndex)
|
||||||
.Source()
|
.Source()
|
||||||
@ -373,27 +372,12 @@ 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>();
|
if (orderNos.Count < 1) return new List<TrackDetailsIndex>();
|
||||||
|
|
||||||
var r = await Context.SearchAsync<TrackDetailsIndex>(x => x
|
var musts = new List<Func<QueryContainerDescriptor<TrackDetailsIndex>, QueryContainer>>
|
||||||
.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)
|
|
||||||
))
|
|
||||||
.Query(q =>
|
|
||||||
q.Bool(b => b
|
|
||||||
.Must(
|
|
||||||
mu => mu.Term(f => f.SubSystemId, subSystemId),
|
mu => mu.Term(f => f.SubSystemId, subSystemId),
|
||||||
mu => mu
|
mu => mu
|
||||||
.Terms(t => t
|
.Terms(t => t
|
||||||
@ -402,7 +386,24 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
|||||||
),
|
),
|
||||||
mu => mu
|
mu => mu
|
||||||
.Term(f => f.OrderType, orderType)
|
.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()
|
||||||
|
.Query(q =>
|
||||||
|
q.Bool(b => b
|
||||||
|
.Must(musts)
|
||||||
// tips:对外不暴露服务商轨迹
|
// tips:对外不暴露服务商轨迹
|
||||||
.MustNot(mn => mn
|
.MustNot(mn => mn
|
||||||
.Term(t => t.TrackCode.Suffix("keyword"), GlobalConst.EmptyString)
|
.Term(t => t.TrackCode.Suffix("keyword"), GlobalConst.EmptyString)
|
||||||
@ -418,7 +419,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
|||||||
$"轨迹查询失败,orderType:{orderType},orderNos:{orderNos},原因:{r.DebugInformation}。");
|
$"轨迹查询失败,orderType:{orderType},orderNos:{orderNos},原因:{r.DebugInformation}。");
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Documents.ToList();
|
return r.ToIdList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<TrackDetailsIndex>> GetListAsync(int orderId)
|
public async Task<List<TrackDetailsIndex>> GetListAsync(int orderId)
|
||||||
@ -429,7 +430,10 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
|||||||
q.Term(t => t.OrderId, orderId)
|
q.Term(t => t.OrderId, orderId)
|
||||||
)
|
)
|
||||||
.Size(SafelyLimit)
|
.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)
|
if (!r.IsValid)
|
||||||
{
|
{
|
||||||
@ -462,7 +466,10 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
|
|||||||
.Index(GlobalConst.TrackDetailsIndex)
|
.Index(GlobalConst.TrackDetailsIndex)
|
||||||
.Query(q => query)
|
.Query(q => query)
|
||||||
.Size(SafelyLimit)
|
.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)
|
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)
|
public async Task<List<TrackPushRecordIndex>> GetTrackPushRecordsAsync(int orderId)
|
||||||
{
|
{
|
||||||
@ -56,19 +68,46 @@ public class TrackPushRecordEsRepository : ElasticSearchContextAbstract<TrackPus
|
|||||||
.Size(1000)
|
.Size(1000)
|
||||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
.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
|
var data = await Context.SearchAsync<TrackPushRecordIndex>(x => x
|
||||||
.Index(GlobalConst.TrackPushRecordIndex)
|
.Index(GlobalConst.TrackPushRecordIndex)
|
||||||
.Query(q =>
|
.Query(q =>
|
||||||
q.Term(t => t.OrderId, orderId)
|
q.Bool(b =>
|
||||||
|
b.Must(musts))
|
||||||
)
|
)
|
||||||
.Size(1000)
|
.Size(1000)
|
||||||
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)));
|
||||||
|
|
||||||
return data.Documents.FirstOrDefault();
|
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,
|
ContentCn = b.Content,
|
||||||
ContentEn = b.EnContent,
|
ContentEn = b.EnContent,
|
||||||
Status = c.Status,
|
Status = c.Status,
|
||||||
Node = d.NodeName
|
Node = d.NodeName,
|
||||||
|
Sort = a.Sort
|
||||||
})
|
})
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
@ -222,7 +223,8 @@ public class TrackTemplateRepository : BasicRepository<TrackTemplateEntity>, ITr
|
|||||||
{
|
{
|
||||||
var templateContents = contents.Where(x => x.TemplateId == template.Id).ToList();
|
var templateContents = contents.Where(x => x.TemplateId == template.Id).ToList();
|
||||||
|
|
||||||
template.TemplateContents = templateContents;
|
//根据排序键排序
|
||||||
|
template.TemplateContents = templateContents.OrderBy(x => x.Sort).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return templates;
|
return templates;
|
||||||
@ -262,10 +264,13 @@ public class TrackTemplateRepository : BasicRepository<TrackTemplateEntity>, ITr
|
|||||||
ContentCn = b.Content,
|
ContentCn = b.Content,
|
||||||
ContentEn = b.EnContent,
|
ContentEn = b.EnContent,
|
||||||
Status = c.Status,
|
Status = c.Status,
|
||||||
Node = d.NodeName
|
Node = d.NodeName,
|
||||||
|
Sort = a.Sort
|
||||||
})
|
})
|
||||||
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
.ToPagedListAsync(input.PageIndex, input.PageSize);
|
||||||
|
|
||||||
|
//返回轨迹模板内容时按排序键排序
|
||||||
|
contents.List = contents.List.OrderBy(x => x.Sort).ToList();
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user