diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningDetailsDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningDetailsDto.cs
index 0bd2961d..b2c0d5be 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningDetailsDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningDetailsDto.cs
@@ -3,104 +3,104 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Complete;
///
/// 完整预警
///
-public class CompleteWarningDetailsDto // todo:需要根据状态排序
+public class CompleteWarningDetailsDto
{
- ///
- /// 预警明细唯一id
- ///
- public string EsId { get; set; }
+ ///
+ /// 预警明细唯一id
+ ///
+ public string EsId { get; set; }
- ///
- /// 子系统id
- ///
- public int SubSystemId { get; set; }
+ ///
+ /// 子系统id
+ ///
+ public int SubSystemId { get; set; }
- ///
- /// 子系统名称
- ///
- public string SubSystemName { get; set; } // todo:id换名称
+ ///
+ /// 子系统名称
+ ///
+ public string SubSystemName { get; set; } // todo:id换名称
- ///
- /// 订单类型
- ///
- public int OrderType { get; set; }
+ ///
+ /// 订单类型
+ ///
+ public int OrderType { get; set; }
- ///
- /// 订单类型名称
- ///
- public string OrderTypeName { get; set; } // todo:type换名称
+ ///
+ /// 订单类型名称
+ ///
+ public string OrderTypeName { get; set; } // todo:type换名称
- ///
- /// 订单id
- ///
- public int OrderId { get; set; }
+ ///
+ /// 订单id
+ ///
+ public int OrderId { get; set; }
- ///
- /// 订单号
- ///
- public string OrderNo { get; set; }
+ ///
+ /// 订单号
+ ///
+ public string OrderNo { get; set; }
- ///
- /// 状态 (待处理样式标红)
- /// 1:待处理,2:已处理,3:已关闭
- ///
- public int Status { get; set; }
+ ///
+ /// 状态 (待处理样式标红)
+ /// 1:待处理,2:已处理,3:已关闭
+ ///
+ public int Status { get; set; }
- ///
- /// 客户id
- ///
- public int CustomId { get; set; }
+ ///
+ /// 客户id
+ ///
+ public int CustomId { get; set; }
- ///
- /// 客户简称
- ///
- public int CustomName { get; set; } // todo:id换名称
+ ///
+ /// 客户简称
+ ///
+ public string CustomName { get; set; }
- ///
- /// 缺失轨迹状态
- ///
- public string MissingTrackStatus { get; set; } // todo:id换名称
+ ///
+ /// 缺失轨迹状态
+ ///
+ public string MissingTrackStatus { get; set; } // todo:id换名称
- //视图属性 todo:可以从订单主表拿到
+ //视图属性 tips:从es即时拿取
- ///
- /// 最新轨迹状态
- ///
- public string LatestTrackStatus { get; set; }
+ ///
+ /// 最新轨迹状态
+ ///
+ public string? LatestTrackStatus { get; set; }
- ///
- /// 最新轨迹内容
- ///
- public string LatestTrackContent { get; set; }
+ ///
+ /// 最新轨迹内容
+ ///
+ public string? LatestTrackContent { get; set; }
- ///
- /// 最新轨迹发生地
- ///
- public string LatestTrackPlace { get; set; }
+ ///
+ /// 最新轨迹发生地
+ ///
+ public string? LatestTrackPlace { get; set; }
- ///
- /// 最新轨迹发生时间
- ///
- public DateTime LatestTrackTime { get; set; }
+ ///
+ /// 最新轨迹发生时间
+ ///
+ public DateTime? LatestTrackTime { get; set; }
- ///
- /// 最新轨迹发生时区
- ///
- public float LatestTrackTimeZone { get; set; }
+ ///
+ /// 最新轨迹发生时区
+ ///
+ public float? LatestTrackTimeZone { get; set; }
- ///
- /// 通知对象
- ///
- public string NotifyUserNames { get; set; }
+ ///
+ /// 通知对象
+ ///
+ public string NotifyUserNames { get; set; }
- ///
- /// 预警创建时间
- ///
- public DateTime CreateTime { get; set; }
+ ///
+ /// 预警创建时间
+ ///
+ public DateTime CreateTime { get; set; }
- ///
- /// 预警处理时间
- ///
- public DateTime? ProcessedTime { get; set; }
+ ///
+ /// 预警处理时间
+ ///
+ public DateTime? ProcessedTime { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningRuleItemDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningRuleItemDto.cs
index 2e4e0335..7de3d710 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningRuleItemDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/CompleteWarningRuleItemDto.cs
@@ -1,4 +1,3 @@
-using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Return;
namespace SJZY.Track.Application.Contract.Dtos.Warning.Complete;
@@ -21,7 +20,7 @@ public class CompleteWarningRuleItemDto
///
/// 订单类型 e.g FBA订单、海运单
///
- public List OrderType { get; set; }
+ public List OrderTypes { get; set; }
///
/// 检查点轨迹状态id
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/EditCompleteWarningRuleItemInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/EditCompleteWarningRuleItemInput.cs
index 80ab9829..a53c5b19 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/EditCompleteWarningRuleItemInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Complete/EditCompleteWarningRuleItemInput.cs
@@ -8,16 +8,16 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Complete;
///
public class EditCompleteWarningRuleItemInput
{
- ///
- /// 预警规主体id
- ///
- [IdRequired]
- public int WarningId { get; set; }
+ ///
+ /// 预警规主体id
+ ///
+ [IdRequired]
+ public int WarningId { get; set; }
- ///
- /// 预警规则配置项目(列表内容传递)
- ///
- public List Items { get; set; } = new();
+ ///
+ /// 预警规则配置项目(列表内容传递)
+ ///
+ public List Items { get; set; } = new();
}
///
@@ -25,35 +25,35 @@ public class EditCompleteWarningRuleItemInput
///
public class EditCompleteWarningRuleItemDto
{
- ///
- /// 规则项目唯一id(传0视为新增)
- ///
- public int Id { get; set; }
+ ///
+ /// 规则项目唯一id(传0视为新增)
+ ///
+ public int Id { get; set; }
- ///
- /// 订单类型集合(,分割) e.g. 1,2,3
- ///
- [Required]
- public string OrderTypes { get; set; }
+ ///
+ /// 订单类型集合(,分割) e.g. 1,2,3
+ ///
+ [Required]
+ public string OrderTypes { get; set; }
- ///
- /// 检查点轨迹状态id
- ///
- [IdRequired]
- public int CheckPointTrackStatusId { get; set; }
+ ///
+ /// 检查点轨迹状态id
+ ///
+ [IdRequired]
+ public int CheckPointTrackStatusId { get; set; }
- ///
- /// 要求的轨迹状态id集合 e.g. [[1,3],[5,7]]
- /// required: 集合元素(子集合)不要有交集!
- ///
- [Required]
- [MinLength(1, ErrorMessage = "要求的轨迹状态id集合不能为空")]
- public List> RequireTrackStatus { get; set; }
+ ///
+ /// 要求的轨迹状态id集合 e.g. [[1,3],[5,7]]
+ /// required: 集合元素(子集合)不要有交集!
+ ///
+ [Required]
+ [MinLength(1, ErrorMessage = "要求的轨迹状态id集合不能为空")]
+ public List> RequireTrackStatus { get; set; }
- ///
- /// 通知对象用户集合
- ///
- [Required]
- [MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
- public List NotifyUsers { get; set; } = new();
+ ///
+ /// 通知对象用户集合
+ ///
+ [Required]
+ [MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
+ public List NotifyUsers { get; set; } = new();
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/DataAnnotations/IdRequiredAttribute.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/DataAnnotations/IdRequiredAttribute.cs
index 199ba7e8..cd4767f8 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/DataAnnotations/IdRequiredAttribute.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/DataAnnotations/IdRequiredAttribute.cs
@@ -8,9 +8,9 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.DataAnnotations;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class IdRequiredAttribute : RangeAttribute
{
- public IdRequiredAttribute()
- : base(1, int.MaxValue)
- {
- ErrorMessage = "{0} is required and must be greater than 0";
- }
+ public IdRequiredAttribute()
+ : base(1, int.MaxValue)
+ {
+ ErrorMessage = "{0} is required and must be greater than 0";
+ }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/NotifyUserDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/NotifyUserDto.cs
index 55548ac7..ec7d43af 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/NotifyUserDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/NotifyUserDto.cs
@@ -5,15 +5,15 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning;
public sealed class NotifyUserDto
{
- ///
- /// 用户id
- ///
- [IdRequired]
- public int UserId { get; set; }
+ ///
+ /// 用户id
+ ///
+ [IdRequired]
+ public int UserId { get; set; }
- ///
- /// 用户名
- ///
- [Required]
- public string UserName { get; set; }
+ ///
+ /// 用户名
+ ///
+ [Required]
+ public string UserName { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/EditReturnWarningRuleItemInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/EditReturnWarningRuleItemInput.cs
index 16e34ed7..3af60ebe 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/EditReturnWarningRuleItemInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/EditReturnWarningRuleItemInput.cs
@@ -8,16 +8,16 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Return;
///
public class EditReturnWarningRuleItemInput
{
- ///
- /// 预警规主体id
- ///
- [IdRequired]
- public int WarningId { get; set; }
+ ///
+ /// 预警规主体id
+ ///
+ [IdRequired]
+ public int WarningId { get; set; }
- ///
- /// 预警规则配置项目(列表内容传递)
- ///
- public List Items { get; set; } = new();
+ ///
+ /// 预警规则配置项目(列表内容传递)
+ ///
+ public List Items { get; set; } = new();
}
///
@@ -25,26 +25,26 @@ public class EditReturnWarningRuleItemInput
///
public class EditReturnWarningRuleItemDto
{
- ///
- /// 唯一id(传0视为新增)
- ///
- public int Id { get; set; }
+ ///
+ /// 唯一id(传0视为新增)
+ ///
+ public int Id { get; set; }
- ///
- /// 轨迹状态Id集合(,分割)
- ///
- [Required]
- public string TrackStatusIds { get; set; }
+ ///
+ /// 轨迹状态Id集合(,分割)
+ ///
+ [Required]
+ public string TrackStatusIds { get; set; }
- ///
- /// 时效(单位h)
- ///
- [Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
- public float ReturnTimeSpan { get; set; }
+ ///
+ /// 时效(单位h)
+ ///
+ [Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
+ public float ReturnTimeSpan { get; set; }
- ///
- /// 通知对象用户集合
- ///
- [MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
- public List NotifyUsers { get; set; } = new();
+ ///
+ /// 通知对象用户集合
+ ///
+ [MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
+ public List NotifyUsers { get; set; } = new();
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/ReturnWarningDetailsDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/ReturnWarningDetailsDto.cs
index 1165d6b9..8036fc15 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/ReturnWarningDetailsDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Return/ReturnWarningDetailsDto.cs
@@ -2,7 +2,6 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Return;
///
/// 回传预警明细
-/// todo:需要根据状态排序
///
public sealed class ReturnWarningDetailsDto
{
@@ -17,7 +16,7 @@ public sealed class ReturnWarningDetailsDto
public int SubSystemId { get; set; }
///
- /// 子系统名称
+ /// 子系统名称
///
public string SubSystemName { get; set; } // todo:id换名称
@@ -27,7 +26,7 @@ public sealed class ReturnWarningDetailsDto
public int OrderType { get; set; }
///
- /// 订单类型名称
+ /// 订单类型名称
///
public string OrderTypeName { get; set; } // todo:type换名称
@@ -52,17 +51,17 @@ public sealed class ReturnWarningDetailsDto
public int CustomId { get; set; }
///
- /// 客户简称
+ /// 客户简称
///
- public string CustomName { get; set; } // todo:id换名称
+ public string CustomName { get; set; } // todo:id换名称
///
- /// 轨迹状态
+ /// 轨迹状态
///
public string TrackStatus { get; set; }
///
- /// 轨迹代码
+ /// 轨迹代码
///
public string TrackCode { get; set; }
@@ -87,7 +86,7 @@ public sealed class ReturnWarningDetailsDto
public string PushTrackContent { get; set; }
///
- /// 轨迹发生地
+ /// 轨迹发生地
///
public string TrackPlace { get; set; }
@@ -112,7 +111,7 @@ public sealed class ReturnWarningDetailsDto
public DateTime? TrackReturnTime { get; set; }
///
- /// 回传时效
+ /// 回传时效 (单位h)
///
public float? ReturnTimeSpan { get; set; }
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/EditTransportWarningSceneRuleItemInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/EditTransportWarningSceneRuleItemInput.cs
index 5471b64c..fedef9e6 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/EditTransportWarningSceneRuleItemInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/EditTransportWarningSceneRuleItemInput.cs
@@ -5,22 +5,22 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
public class EditTransportWarningSceneRuleItemInput
{
- ///
- /// 预警规主体id
- ///
- [IdRequired]
- public int WarningId { get; set; }
+ ///
+ /// 预警规主体id
+ ///
+ [IdRequired]
+ public int WarningId { get; set; }
- ///
- /// 运输预警场景id
- ///
- [IdRequired]
- public int SceneId { get; set; }
+ ///
+ /// 运输预警场景id
+ ///
+ [IdRequired]
+ public int SceneId { get; set; }
- ///
- /// 预警规则配置项目(列表内容传递)
- ///
- public List Items { get; set; } = new();
+ ///
+ /// 预警规则配置项目(列表内容传递)
+ ///
+ public List Items { get; set; } = new();
}
///
@@ -28,38 +28,38 @@ public class EditTransportWarningSceneRuleItemInput
///
public class EditTransportWarningSceneRuleItemDto
{
- ///
- /// 规则项目id(传0视为新增)
- ///
- public int Id { get; set; }
+ ///
+ /// 规则项目id(传0视为新增)
+ ///
+ public int Id { get; set; }
- ///
- /// 起始轨迹状态Id
- ///
- [IdRequired]
- public int StartTrackStatusId { get; set; }
+ ///
+ /// 起始轨迹状态Id
+ ///
+ [IdRequired]
+ public int StartTrackStatusId { get; set; }
- ///
- /// 截止轨迹状态Id
- ///
- [IdRequired]
- public int EndTrackStatusId { get; set; }
+ ///
+ /// 截止轨迹状态Id
+ ///
+ [IdRequired]
+ public int EndTrackStatusId { get; set; }
- ///
- /// 时效 (单位h)
- ///
- [Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
- public float TransportTimeSpan { get; set; }
+ ///
+ /// 时效 (单位h)
+ ///
+ [Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
+ public float TransportTimeSpan { get; set; }
- ///
- /// 起始轨迹生成预警时间 (单位h)
- ///
- [Range(0.1, float.MaxValue, ErrorMessage = "起始轨迹生成预警时间必须大于0.1")]
- public float StartTrackWarningTimeSpan { get; set; }
+ ///
+ /// 起始轨迹生成预警时间 (单位h)
+ ///
+ [Range(0.1, float.MaxValue, ErrorMessage = "起始轨迹生成预警时间必须大于0.1")]
+ public float StartTrackWarningTimeSpan { get; set; }
- ///
- /// 通知对象用户集合
- ///
- [MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
- public List NotifyUsers { get; set; } = new();
+ ///
+ /// 通知对象用户集合
+ ///
+ [MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
+ public List NotifyUsers { get; set; } = new();
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneInput.cs
index 0b9bcebe..13fde467 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneInput.cs
@@ -7,9 +7,9 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
///
public class GetTransportWarningSceneInput
{
- ///
- /// 预警主体id
- ///
- [IdRequired]
- public int WarningId { get; set; }
+ ///
+ /// 预警主体id
+ ///
+ [IdRequired]
+ public int WarningId { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneRuleItemInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneRuleItemInput.cs
index f1c7f56a..6538d1e4 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneRuleItemInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/GetTransportWarningSceneRuleItemInput.cs
@@ -7,15 +7,15 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
///
public class GetTransportWarningSceneRuleItemInput
{
- ///
- /// 预警主体id
- ///
- [IdRequired]
- public int WarningId { get; set; }
+ ///
+ /// 预警主体id
+ ///
+ [IdRequired]
+ public int WarningId { get; set; }
- ///
- /// 运输预警场景id
- ///
- [IdRequired]
- public int SceneId { get; set; }
+ ///
+ /// 运输预警场景id
+ ///
+ [IdRequired]
+ public int SceneId { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningDetailsDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningDetailsDto.cs
index 4b4e01b8..1ef707f3 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningDetailsDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningDetailsDto.cs
@@ -5,145 +5,145 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
///
public sealed class TransportWarningDetailsDto // todo:需要根据状态排序
{
- ///
- /// 预警明细唯一id
- ///
- public string EsId { get; set; }
+ ///
+ /// 预警明细唯一id
+ ///
+ public string EsId { get; set; }
- ///
- /// 子系统id
- ///
- public int SubSystemId { get; set; }
+ ///
+ /// 子系统id
+ ///
+ public int SubSystemId { get; set; }
- ///
- /// 子系统名称
- ///
- public string SubSystemName { get; set; } // todo:id换名称
+ ///
+ /// 子系统名称
+ ///
+ public string SubSystemName { get; set; } // todo:id换名称
- ///
- /// 客户id
- ///
- public int CustomId { get; set; }
+ ///
+ /// 客户id
+ ///
+ public int CustomId { get; set; }
- ///
- /// 客户简称
- ///
- public string CustomName { get; set; } // todo:id换名称
+ ///
+ /// 客户简称
+ ///
+ public string CustomName { get; set; } // todo:id换名称
- ///
- /// 订单id
- ///
- public int OrderId { get; set; }
+ ///
+ /// 订单id
+ ///
+ public int OrderId { get; set; }
- ///
- /// 订单号
- ///
- public string OrderNo { get; set; }
+ ///
+ /// 订单号
+ ///
+ public string OrderNo { get; set; }
- ///
- /// 订单类型
- ///
- public int OrderType { get; set; }
+ ///
+ /// 订单类型
+ ///
+ public int OrderType { get; set; }
- ///
- /// 订单类型名称
- ///
- public string OrderTypeName { get; set; } // todo:type换名称
+ ///
+ /// 订单类型名称
+ ///
+ public string OrderTypeName { get; set; } // todo:type换名称
- // 实时属性 todo:从订单查询
+ // 实时属性 todo:从es查询
- ///
- /// 最新轨迹内容
- ///
- public string LatestTrackContent { get; set; }
+ ///
+ /// 最新轨迹内容
+ ///
+ public string? LatestTrackContent { get; set; }
- ///
- /// 最新轨迹时间
- ///
- public DateTime LatestTrackTime { get; set; }
+ ///
+ /// 最新轨迹时间
+ ///
+ public DateTime? LatestTrackTime { get; set; }
- ///
- /// 最新轨迹发生时区
- ///
- public float LatestTrackTimeZone { get; set; }
+ ///
+ /// 最新轨迹发生时区
+ ///
+ public float? LatestTrackTimeZone { get; set; }
- ///
- /// 最新轨迹发生地
- ///
- public string LatestTrackPlace { get; set; }
+ ///
+ /// 最新轨迹发生地
+ ///
+ public string? LatestTrackPlace { get; set; }
- ///
- /// 通知对象
- ///
- public string NotifyUserNames { get; set; }
+ ///
+ /// 通知对象
+ ///
+ public string NotifyUserNames { get; set; }
- ///
- /// 起始轨迹状态
- ///
- public string StartTrackStatus { get; set; }
+ ///
+ /// 起始轨迹状态
+ ///
+ public string StartTrackStatus { get; set; }
- ///
- /// 起始轨迹内容
- ///
- public string StartTrackContent { get; set; }
+ ///
+ /// 起始轨迹内容
+ ///
+ public string StartTrackContent { get; set; }
- ///
- /// 起始轨迹发生时间
- ///
- public DateTime StartTrackTime { get; set; }
+ ///
+ /// 起始轨迹发生时间
+ ///
+ public DateTime StartTrackTime { get; set; }
- ///
- /// 起始轨迹时区
- ///
- public float StartTrackTimeZone { get; set; }
+ ///
+ /// 起始轨迹时区
+ ///
+ public float StartTrackTimeZone { get; set; }
- ///
- /// 截止轨迹状态
- ///
- public string EndTrackStatus { get; set; }
+ ///
+ /// 截止轨迹状态
+ ///
+ public string EndTrackStatus { get; set; }
- ///
- /// 截止轨迹内容
- ///
- public string? EndTrackContent { get; set; }
+ ///
+ /// 截止轨迹内容
+ ///
+ public string? EndTrackContent { get; set; }
- ///
- /// 截止轨迹发生时间
- ///
- public DateTime? EndTrackTime { get; set; }
+ ///
+ /// 截止轨迹发生时间
+ ///
+ public DateTime? EndTrackTime { get; set; }
- ///
- /// 截止轨迹时区
- ///
- public float? EndTrackTimeZone { get; set; }
+ ///
+ /// 截止轨迹时区
+ ///
+ public float? EndTrackTimeZone { get; set; }
- ///
- /// 预警名称 (预警主体名称 如字节全程时效)
- ///
- public string WarningName { get; set; }
+ ///
+ /// 预警名称 (预警主体名称 如字节全程时效)
+ ///
+ public string WarningName { get; set; }
- ///
- /// 预警规则描述(用于tooltip展示)
- ///
- public string WarningRuleDescription { get; set; }
+ ///
+ /// 预警规则描述(用于tooltip展示)
+ ///
+ public string WarningRuleDescription { get; set; }
- ///
- /// 累计运输时间
- ///
- public string CumulativeTimeSpan { get; set; } // todo:需要转换为某个格式
+ ///
+ /// 累计运输时间
+ ///
+ public string CumulativeTimeSpan { get; set; } // todo:需要转换为某个格式
- ///
- /// 预警状态 (根据key展示对应名称,即将超时需要标红)
- /// 1:即将超时 2:已超时 3:已完成 4:超时完成 5:已关闭,初始为【即将超时】
- ///
- public int Status { get; set; }
+ ///
+ /// 预警状态 (根据key展示对应名称,即将超时需要标红)
+ /// 1:即将超时 2:已超时 3:已完成 4:超时完成 5:已关闭,初始为【即将超时】
+ ///
+ public int Status { get; set; }
- ///
- /// 预警创建时间
- ///
- public DateTime CreateTime { get; set; }
+ ///
+ /// 预警创建时间
+ ///
+ public DateTime CreateTime { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneDto.cs
index 4aaf36ec..d4ddf002 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneDto.cs
@@ -16,7 +16,7 @@ public class TransportWarningSceneDto
public int WarningId { get; set; }
///
- /// 场景摘要(用于展示场景tabs)
+ /// 场景摘要(用于展示场景tabs)
///
public string Summary { get; set; } // todo:将规则场景一些列因素转换为一段描述
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneRuleItemDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneRuleItemDto.cs
index b5d84089..d0c1a94b 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneRuleItemDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/TransportWarningSceneRuleItemDto.cs
@@ -1,5 +1,3 @@
-using SJZY.Track.Application.Contract.Dtos.Warning;
-
namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
///
@@ -46,4 +44,4 @@ public class TransportWarningSceneRuleItemDto
/// 通知对象用户集合
///
public List NotifyUsers { get; set; } = new();
-}
\ No newline at end of file
+}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/UpsertTransportWarningSceneInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/UpsertTransportWarningSceneInput.cs
index cc27b52a..07d64f2f 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/UpsertTransportWarningSceneInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/Transport/UpsertTransportWarningSceneInput.cs
@@ -1,7 +1,8 @@
using SJZY.Track.Application.Contract.Dtos.Warning.DataAnnotations;
+
namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
-public class UpsertTransportWarningSceneInput
+public sealed class UpsertTransportWarningSceneInput
{
///
/// 场景唯一id (传0视为新增)
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/UpsertWarningRuleInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/UpsertWarningRuleInput.cs
index 2c5d8f87..8d226d4a 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/UpsertWarningRuleInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/UpsertWarningRuleInput.cs
@@ -8,38 +8,38 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning;
///
public class UpsertWarningRuleInput
{
- ///
- /// 唯一id(传0视为新增)
- ///
- public int Id { get; set; }
+ ///
+ /// 唯一id(传0视为新增)
+ ///
+ public int Id { get; set; }
- ///
- /// 子系统id
- ///
- [IdRequired]
- public int SubSystemId { get; set; } //子系统id
+ ///
+ /// 子系统id
+ ///
+ [IdRequired]
+ public int SubSystemId { get; set; } //子系统id
- ///
- /// 客户id
- ///
- [IdRequired]
- public int CustomId { get; set; } //客户id
+ ///
+ /// 客户id
+ ///
+ [IdRequired]
+ public int CustomId { get; set; } //客户id
- ///
- /// 预警规则名称
- ///
- [Required]
- public string Name { get; set; }
+ ///
+ /// 预警规则名称
+ ///
+ [Required]
+ public string Name { get; set; }
- ///
- /// 是否启用
- ///
- [Required]
- public bool IsEnabled { get; set; }
+ ///
+ /// 是否启用
+ ///
+ [Required]
+ public bool IsEnabled { get; set; }
- ///
- /// 预警类型,1:运输时效,2:回传时效,3:完整预警
- ///
- [Range(1, 3, ErrorMessage = "预警类型只能选取以下值,1:运输时效,2:回传时效,3:完整预警")]
- public int WarningType { get; set; }
+ ///
+ /// 预警类型,1:运输时效,2:回传时效,3:完整预警
+ ///
+ [Range(1, 3, ErrorMessage = "预警类型只能选取以下值,1:运输时效,2:回传时效,3:完整预警")]
+ public int WarningType { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/Warning/WarningRuleDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Warning/WarningRuleDto.cs
index 57ea30fe..6b71a42a 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/Warning/WarningRuleDto.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/Warning/WarningRuleDto.cs
@@ -13,22 +13,22 @@ public sealed class WarningRuleDto
///
/// 子系统id
///
- public int SubSystemId { get; set; } //子系统id
+ public int SubSystemId { get; set; } //子系统id
///
- /// 子系统名称
+ /// 子系统名称
///
- public int SubSystemName { get; set; } // todo:id换name
+ public string SubSystemName { get; set; }
///
/// 客户id
///
- public int CustomId { get; set; } //客户id
+ public int CustomId { get; set; } //客户id
///
- /// 客户简称
+ /// 客户简称
///
- public int CustomName { get; set; } // todo:id换name
+ public string CustomName { get; set; }
///
/// 预警规则名称
diff --git a/src/SJZY.Track.Application/AutoMapper/WarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/WarningMapperProfile.cs
new file mode 100644
index 00000000..4fef273f
--- /dev/null
+++ b/src/SJZY.Track.Application/AutoMapper/WarningMapperProfile.cs
@@ -0,0 +1,17 @@
+using AutoMapper;
+using SJZY.Track.Application.Contract.Dtos.Warning.Complete;
+using SJZY.Track.Application.Contract.Dtos.Warning.Return;
+using SJZY.Track.Application.Contract.Dtos.Warning.Transport;
+using SJZY.Track.Domain.Dtos.Warning;
+
+namespace SJZY.Track.Application.AutoMapper;
+
+public class WarningMapperProfile : Profile
+{
+ public WarningMapperProfile()
+ {
+ CreateMap(MemberList.None);
+ CreateMap(MemberList.None);
+ CreateMap(MemberList.None);
+ }
+}
diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs
index 5ce98e81..ca773013 100644
--- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs
+++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs
@@ -10,6 +10,7 @@ using SJZY.Track.Application.Helpers;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Enums;
+using SJZY.Track.Domain.Extensions;
using SJZY.Track.Domain.Queries;
using Volo.Abp.DependencyInjection;
diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs
index 110f5c73..72b5a080 100644
--- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs
+++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs
@@ -15,6 +15,7 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Enums;
+using SJZY.Track.Domain.Extensions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.DynamicProxying;
diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs
index 9bc5140a..2bd5112c 100644
--- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs
+++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs
@@ -10,6 +10,7 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Dtos.TrackContents;
using SJZY.Track.Domain.Enums;
+using SJZY.Track.Domain.Extensions;
using SJZY.Track.Domain.Queries;
using Volo.Abp.DependencyInjection;
using OrderIdentifier = SJZY.Track.Application.Contract.Events.OrderIdentifier;
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs
index ca74ebe4..119e8c25 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs
@@ -10,6 +10,7 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Dtos.TrackPush;
+using SJZY.Track.Domain.Extensions;
using SJZY.Track.Domain.Queries;
using SJZY.UserCenter.HttpApi.Services.User;
using Volo.Abp.Http.Client.DynamicProxying;
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
index d6e268a8..1931a805 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
@@ -9,6 +9,7 @@ using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
using SJZY.Track.Domain.Enums;
+using SJZY.Track.Domain.Extensions;
using SJZY.Track.Domain.Queries;
using SJZY.UserCenter.HttpApi.Services;
using SJZY.UserCenter.HttpApi.Services.User;
diff --git a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs
index 89041d1f..df7553fc 100644
--- a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs
+++ b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs
@@ -67,7 +67,7 @@ public class TrackOrderService : ApplicationService
[HttpGet("GetOrderTypeDict")]
public async Task> GetOrderTypeDict()
{
- return await _orderRepository.GetTrackOrderTypeDict();
+ return await _orderRepository.GetTrackOrderTypeDictAsync();
}
///
diff --git a/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs b/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs
index fcf66ef8..f36b1c62 100644
--- a/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs
+++ b/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs
@@ -57,7 +57,7 @@ public class TrackPushService : ApplicationService, ISingletonDependency
{
var orderTypes = await _trackPushConfigRepository.GetConfigTags(inputVo);
if (orderTypes.Count == 0) return new List();
- var trackOrderTypes = await _orderRepository.GetTrackOrderTypeDict();
+ var trackOrderTypes = await _orderRepository.GetTrackOrderTypeDictAsync();
return orderTypes.Select(x => new TrackPushConfigTagDto
{
diff --git a/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs b/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs
index dbdb41d9..2a52edbf 100644
--- a/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/CompleteWarningService.cs
@@ -1,4 +1,18 @@
+using SJZY.Expand.ABP.Core.PublicMethords;
+using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Complete;
+using SJZY.Track.Application.Contract.Dtos.Warning.Return;
+using SJZY.Track.Application.Helpers;
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Application.Services.Warning.Handlers.Warning;
+using SJZY.Track.Domain.Aggregates.OrderAggregate;
+using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
+using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
+using SJZY.Track.Domain.Dtos.Warning;
+using SJZY.Track.Domain.Enums;
+using SJZY.Track.Domain.Extensions;
namespace SJZY.Track.Application.Services.Warning;
@@ -9,15 +23,21 @@ namespace SJZY.Track.Application.Services.Warning;
[Route("Warning/Complete")]
public class CompleteWarningService : ApplicationService
{
- ///
- /// 编辑完整预警规则列表
- ///
- ///
- ///
- [HttpPost("EditCompleteWarningRuleItem")]
- public Task EditCompleteWarningRuleItem(EditCompleteWarningRuleItemInput input)
+ private readonly IOrderRepository _orderRepository;
+ private readonly IWarningRuleRepository _warningRuleRepository;
+ private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
+ private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
+ private readonly ICompleteWarningHandler _completeWarningHandler;
+ private readonly ITrackStatusRepository _trackStatusRepository;
+
+ public CompleteWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, ITrackDetailsEsRepository trackDetailsEsRepository, ICompleteWarningHandler completeWarningHandler, ITrackStatusRepository trackStatusRepository, IOrderRepository orderRepository)
{
- return Task.FromResult(new UnifyResultDto());
+ _warningRuleRepository = warningRuleRepository;
+ _warningDetailsEsRepository = warningDetailsEsRepository;
+ _trackDetailsEsRepository = trackDetailsEsRepository;
+ _completeWarningHandler = completeWarningHandler;
+ _trackStatusRepository = trackStatusRepository;
+ _orderRepository = orderRepository;
}
///
@@ -26,10 +46,70 @@ public class CompleteWarningService : ApplicationService
///
///
[HttpPost("GetCompleteWarningRuleItem")]
- public Task>>
- GetCompleteWarningRuleItem(GetCompleteWarningRuleItemInput input)
+ public async Task>> GetCompleteWarningRuleItem(GetCompleteWarningRuleItemInput input)
{
- return Task.FromResult(new UnifyResultDto>());
+ var result = await _warningRuleRepository.GetCompleteRuleItemsAsync(input.WarningId);
+ if (result.Count == 0)
+ return new UnifyResultDto>(true, new List());
+
+ // todo:缓存优化
+ var trackStatusIds = result
+ .SelectMany(x =>
+ {
+ // todo:逻辑优化
+ var checkStatusId = x.CheckPointTrackStatusId;
+ var requireStatusIds = x.GetRequireTrackStatusIdGroups();
+ requireStatusIds.Add(new HashSet(1)
+ {
+ checkStatusId
+ });
+ return requireStatusIds.SelectMany(y => y);
+ }).ToHashSet();
+
+ var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Status
+ })).ToDictionary(x => x.Id, y => y.Status);
+
+ // 查订单类型映射
+ var orderTypeDict = await _orderRepository.GetTrackOrderTypeDictAsync();
+
+ var map = result.Select(x => new CompleteWarningRuleItemDto
+ {
+ Id = x.Id,
+ WarningId = x.WarningId,
+ OrderTypes = BuildOrderTypes(x),
+ CheckPointTrackStatusId = x.CheckPointTrackStatusId,
+ CheckPointTrackStatus = trackStatusDict.GetValueOrDefault(x.CheckPointTrackStatusId),
+ RequireTrackStatus = BuildRequireTrackStatus(x),
+ NotifyUsers = TextJsonHelper.Deserialize>(x.NotifyUsers)!
+ });
+
+ return new UnifyResultDto>(true, map.ToList());
+
+ List BuildRequireTrackStatus(CompleteWarningRuleItemEntity entity)
+ {
+ return entity.GetRequireTrackStatusIdGroups()
+ .Select(g => new RequireTrackStatusItem
+ {
+ Statuses = g.Select(id => new TrackStatusDto
+ {
+ TrackStatusId = id,
+ TrackStatus = trackStatusDict.GetValueOrDefault(id)
+ }).ToList()
+ }).ToList();
+ }
+
+ List BuildOrderTypes(CompleteWarningRuleItemEntity entity)
+ {
+ return entity.GetRuleOrderTypes()
+ .Select(x => new OrderTypeDto
+ {
+ OrderType = x,
+ OrderTypeName = orderTypeDict.GetValueOrDefault(x.ToString())
+ }).ToList();
+ }
}
///
@@ -38,9 +118,114 @@ public class CompleteWarningService : ApplicationService
///
///
[HttpPost("GetPageCompleteWarningDetails")]
- public Task>
- GetPageCompleteWarningDetails(GetPageCompleteWarningDetailsInput input)
+ public async Task> GetPageCompleteWarningDetails(GetPageCompleteWarningDetailsInput input)
{
- return Task.FromResult(new UnifyPageResultDto());
+ var vo = ObjectMapper.Map(input);
+ var result = await _warningDetailsEsRepository.GetPageCompleteWarningDetailsAsync(vo);
+
+ if (result.List.Count == 0)
+ return new UnifyPageResultDto(new List(), input.PageIndex, input.PageSize, 0);
+
+ // todo:缓存优化
+ var trackStatusIds = result.List
+ .SelectMany(x => x.MissingTrackStatusIds.Split(',').Select(int.Parse))
+ .ToHashSet();
+ var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Status
+ })).ToDictionary(x => x.Id, y => y.Status);
+
+ // 查最新轨迹
+ var orderIds = result.List.Select(x => x.OrderId).ToHashSet();
+ var orderTracks = await _trackDetailsEsRepository.GetLatestListAsync(orderIds);
+ var orderIdTrackDict = orderTracks.ToDictionary(x => x.OrderId);
+
+ // :填充子系统名称(冗余?)
+ // :填充客户简称(冗余?)
+ // :填充订单类型名称(冗余?)
+ var map = result.List.Select(x =>
+ {
+ var orderIdTrack = orderIdTrackDict.GetValueOrDefault(x.OrderId);
+ return new CompleteWarningDetailsDto
+ {
+ EsId = x.Id,
+ SubSystemId = x.SubSystemId,
+ SubSystemName = x.SubSystemName,
+ OrderType = x.OrderType,
+ OrderTypeName = x.OrderTypeName,
+ OrderId = x.OrderId,
+ OrderNo = x.OrderNo,
+ Status = x.Status,
+ CustomId = x.CustomId,
+ CustomName = x.CustomName,
+ MissingTrackStatus = BuildMissingTrackStatus(x.MissingTrackStatusIds),
+ LatestTrackStatus = orderIdTrack?.TrackStatus,
+ LatestTrackContent = orderIdTrack?.TrackContent,
+ LatestTrackPlace = orderIdTrack?.TrackPlace,
+ LatestTrackTime = orderIdTrack?.TrackTime,
+ LatestTrackTimeZone = orderIdTrack?.TrackTimeZone,
+
+ NotifyUserNames = ToUserNames(x.NotifyUsers),
+ CreateTime = x.CreateTime,
+ ProcessedTime = x.ProcessedTime
+ };
+ });
+
+ var sorted = map.OrderBy(x =>
+ {
+ // 待处理置顶
+ if (x.Status == 1) return x.Status;
+ // 其他按创建时间从早到晚
+ return DateTimeHelper.ConvertToUnixTimestamp(x.CreateTime);
+ });
+
+ return new UnifyPageResultDto(
+ sorted.ToList(),
+ result.Pagination.PageIndex,
+ result.Pagination.PageSize,
+ result.Pagination.Total);
+
+ // 通知用户提取用户名称
+ string ToUserNames(string notifyUsers)
+ {
+ if (string.IsNullOrWhiteSpace(notifyUsers))
+ return string.Empty;
+ return string.Join(',', notifyUsers.ToObject>().Select(x => x.UserName));
+ }
+
+ string BuildMissingTrackStatus(string statusIds)
+ {
+ var trackStatus = statusIds.Split(',').Select(x =>
+ {
+ if (int.TryParse(x, out var id))
+ return trackStatusDict.GetValueOrDefault(id)
+ ?? $"丢失{id}轨迹状态";
+
+ return null;
+ }).Where(x => x != null);
+
+ return string.Join(',', trackStatus);
+ }
+ }
+
+
+ ///
+ /// 编辑完整预警规则列表
+ ///
+ ///
+ ///
+ [HttpPost("EditCompleteWarningRuleItem")]
+ public async Task EditCompleteWarningRuleItem(EditCompleteWarningRuleItemInput input)
+ {
+ var rule = await _warningRuleRepository.GetWarningRuleByIdAsync(input.WarningId, WarningRuleType.完整预警);
+ if (rule == null)
+ {
+ throw new BusinessException(message: $"预警规则主体不存在,WarningId=[{input.WarningId}]");
+ }
+
+ var bos = CompleteWarningRuleItemBO.From(input);
+ await _completeWarningHandler.HandleEditAsync(rule, bos);
+ return new UnifyResultDto(true);
}
}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs
new file mode 100644
index 00000000..4dafef7d
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/CompleteWarningHandler.cs
@@ -0,0 +1,170 @@
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Application.Services.Warning.Handlers.Warning;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers;
+
+public sealed class CompleteWarningHandler : ICompleteWarningHandler
+{
+ private readonly IWarningRuleRepository _warningRuleRepository;
+
+ public CompleteWarningHandler(IWarningRuleRepository warningRuleRepository)
+ {
+ _warningRuleRepository = warningRuleRepository;
+ }
+
+ public Task TrackDeletedHandleAsync(List deletedSignals)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task TrackAddedHandleAsync(List addedSignals)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule)
+ {
+ throw new NotImplementedException();
+ }
+
+ #region todo: 规则项目变更
+
+ public async Task HandleEditAsync(WarningRuleEntity rule, List postRuleItems)
+ {
+ var addRuleItems = postRuleItems.Where(x => x.Id == 0).ToList();
+ // 1.找到之前的配置项目
+ var entities = await _warningRuleRepository.GetCompleteRuleItemsAsync(rule.Id);
+ var oldRuleItems = CompleteWarningRuleItemBO.From(entities);
+ // 1.1之前的配置数量为0,做只新增处理
+ if (oldRuleItems.Count == 0)
+ {
+ if (addRuleItems.Count != 0)
+ await OnlyAddHandleAsync(rule, addRuleItems);
+
+ return;
+ }
+
+ // 1.2之前的配置数量不为0,提交的数量为0,做只删除处理
+ if (oldRuleItems.Count != 0 && postRuleItems.Count == 0)
+ {
+ await OnlyDeleteHandleAsync(rule, oldRuleItems);
+ return;
+ }
+
+ // 关心规则修改/删除
+ var updateRuleItems = new List();
+ var deleteRuleItems = new List();
+
+ // 构建id配置项字典
+ var oldDict = oldRuleItems.ToDictionary(x => x.Id);
+ var updateAndAddRuleItems = postRuleItems.Where(x => x.Id == 0).ToList();
+ var postDict = postRuleItems
+ .Except(updateAndAddRuleItems) //tips:差异化比较时忽略新增的规则条目
+ .ToDictionary(x => x.Id);
+
+ // 2.差异化比较
+ var ruleItemIds = oldDict.Keys.Concat(postDict.Keys).ToHashSet();
+ foreach (var ruleItemId in ruleItemIds)
+ {
+ var oldRule = oldDict.GetValueOrDefault(ruleItemId);
+ var postRule = postDict.GetValueOrDefault(ruleItemId);
+ if (oldRule != null && postRule != null)
+ {
+ //规则属性变更,(状态减少,时效变更)
+ if (CanNeedFollow(oldRule, postRule))
+ updateRuleItems.Add(postRule); //更新 关注新配置
+
+ continue;
+ }
+
+ //规则条目被删除
+ if (oldRule != null && postRule == null)
+ deleteRuleItems.Add(oldRule); //删除 关注旧配置
+ }
+
+ // 3.处理变更
+ await HandleRuleItemsChangeAsync(rule, addRuleItems, updateRuleItems, deleteRuleItems);
+ }
+
+ private async Task OnlyDeleteHandleAsync(WarningRuleEntity rule, List bos)
+ {
+ var ruleItemIds = bos.Select(x => x.Id).ToHashSet();
+ await _warningRuleRepository.DeleteCompleteRuleItemsAsync(ruleItemIds);
+
+ // 更新规则主体版本号
+ await _warningRuleRepository.UpdateVersionAsync(rule);
+
+ // todo:暂时不处理后续逻辑
+ return;
+
+ }
+
+ private async Task OnlyAddHandleAsync(WarningRuleEntity rule, List bos)
+ {
+ var entities = CompleteWarningRuleItemBO.ToEntities(bos);
+ await _warningRuleRepository.BulkInsertCompleteRuleItemsAsync(entities);
+ // 更新规则主体版本号
+ await _warningRuleRepository.UpdateVersionAsync(rule);
+ }
+
+ private async Task HandleRuleItemsChangeAsync(
+ WarningRuleEntity rule,
+ List addRuleItems,
+ List updateRuleItems,
+ List deleteRuleItems
+ )
+ {
+ // 新增/修改/删除 实体,稍后做处理
+ var addEntities = CompleteWarningRuleItemBO.ToEntities(addRuleItems);
+ var updateEntities = CompleteWarningRuleItemBO.ToEntities(updateRuleItems);
+ var deleteRuleItemIds = deleteRuleItems.Select(x => x.Id).ToHashSet();
+ await _warningRuleRepository.BulkInsertCompleteRuleItemsAsync(addEntities);
+ await _warningRuleRepository.BulkUpdateCompleteRuleItemsAsync(updateEntities);
+ await _warningRuleRepository.DeleteCompleteRuleItemsAsync(deleteRuleItemIds);
+
+ // todo:暂时不启用后续规则
+ return;
+ }
+
+ private bool CanNeedFollow(CompleteWarningRuleItemBO oldRule, CompleteWarningRuleItemBO postRule)
+ {
+ // 关注的订单类型减少
+ var oldTypes = oldRule.OrderTypes;
+ var postTypes = postRule.OrderTypes;
+ foreach (var type in oldTypes)
+ {
+ if (!postTypes.Contains(type))
+ return true;
+ }
+
+ // 检查点发生变化
+ if (oldRule.CheckPointTrackStatusId != postRule.CheckPointTrackStatusId)
+ return true;
+
+ // 要求的轨迹状态,
+ // 条目内或关系状态变更,比如 案例1:S1/S2,S4 => S1/S3,案例2: S1/S2,S4 => S1,S4
+ // 条目减少,S1/S2,S4 => S1/S2
+ var oldStatusIds = oldRule.RequireTrackStatus.SelectMany(x => x).ToHashSet();
+ var postStatusIds = postRule.RequireTrackStatus.SelectMany(x => x).ToHashSet();
+
+ if (oldStatusIds.Count > postStatusIds.Count) //数量减少,一定需要关注
+ return true;
+
+ foreach (var statusId in oldStatusIds)
+ {
+ if (!postStatusIds.Contains(statusId)) //状态减少,需要关注
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+ public List FilterAndHandleNeedNotifyTask(List notifyTasks)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Model/CompleteWarningRuleItemBO.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/CompleteWarningRuleItemBO.cs
new file mode 100644
index 00000000..31fd5ea3
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/CompleteWarningRuleItemBO.cs
@@ -0,0 +1,91 @@
+using SJZY.Track.Application.Contract.Dtos.Warning;
+using SJZY.Track.Application.Contract.Dtos.Warning.Complete;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
+using SJZY.Track.Domain.Extensions;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Model;
+
+public sealed class CompleteWarningRuleItemBO
+{
+ ///
+ /// 规则项目唯一id(传0视为新增)
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// 预警规主体id
+ ///
+ public int WarningId { get; set; }
+
+ ///
+ /// 订单类型集合(,分割) e.g. 1,2,3
+ ///
+ public HashSet OrderTypes { get; set; }
+
+ ///
+ /// 检查点轨迹状态id
+ ///
+ public int CheckPointTrackStatusId { get; set; }
+
+ ///
+ /// 要求的轨迹状态id集合 e.g. [[1,3],[5,7]]
+ /// required: 集合元素(子集合)不要有交集!
+ ///
+ public List> RequireTrackStatus { get; set; }
+
+ ///
+ /// 通知对象用户集合
+ ///
+ public List NotifyUsers { get; set; } = new();
+
+ public static List From(EditCompleteWarningRuleItemInput input)
+ {
+ return input.Items.Select(x => new CompleteWarningRuleItemBO
+ {
+ Id = x.Id,
+ WarningId = input.WarningId,
+ OrderTypes = x.OrderTypes.Split(",").Select(int.Parse).ToHashSet(),
+ CheckPointTrackStatusId = x.CheckPointTrackStatusId,
+ RequireTrackStatus = x.RequireTrackStatus.Select(y => y.ToHashSet()).ToList(),
+ NotifyUsers = x.NotifyUsers
+ })
+ .ToList();
+ }
+
+ public CompleteWarningRuleItemEntity ToEntity()
+ {
+ var requireTrackStatusIdExpression = string.Join(',', RequireTrackStatus.Select(sub => string.Join('/', sub)));
+
+ return new CompleteWarningRuleItemEntity(
+ Id,
+ WarningId,
+ string.Join(",", OrderTypes),
+ CheckPointTrackStatusId,
+ requireTrackStatusIdExpression,
+ TextJsonHelper.Serialize(NotifyUsers)!
+ );
+ }
+
+ public static List ToEntities(List bos)
+ {
+ return bos.Select(x => x.ToEntity()).ToList();
+ }
+
+ public static CompleteWarningRuleItemBO From(CompleteWarningRuleItemEntity entity)
+ {
+ return new CompleteWarningRuleItemBO
+ {
+ Id = entity.Id,
+ WarningId = entity.WarningId,
+ OrderTypes = entity.GetRuleOrderTypes(),
+ CheckPointTrackStatusId = entity.CheckPointTrackStatusId,
+ RequireTrackStatus = entity.GetRequireTrackStatusIdGroups(),
+ NotifyUsers = TextJsonHelper.Deserialize>(entity.NotifyUsers)!
+ };
+ }
+
+ public static List From(List entities)
+ {
+ return entities.Select(From).ToList();
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Model/ReturnWarningRuleItemBO.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/ReturnWarningRuleItemBO.cs
new file mode 100644
index 00000000..bbe6070c
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/ReturnWarningRuleItemBO.cs
@@ -0,0 +1,81 @@
+using SJZY.Track.Application.Contract.Dtos.Warning;
+using SJZY.Track.Application.Contract.Dtos.Warning.Return;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+using SJZY.Track.Domain.Extensions;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Model;
+
+public sealed class ReturnWarningRuleItemBO
+{
+ ///
+ /// 规则项目唯一id
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// 预警规则主体id
+ ///
+ public int WarningId { get; set; }
+
+ ///
+ /// 轨迹状态
+ ///
+ public HashSet TrackStatusIds { get; set; }
+
+ ///
+ /// 回传预警时间
+ ///
+ public float ReturnTimeSpan { get; set; } //时效(单位小时),只是用于判断状态
+
+ ///
+ /// 通知用户对象集合
+ ///
+ public List NotifyUsers { get; set; }
+
+
+ public static List From(EditReturnWarningRuleItemInput input)
+ {
+ var warningId = input.WarningId;
+ return input.Items.Select(x => new ReturnWarningRuleItemBO
+ {
+ Id = x.Id,
+ WarningId = warningId,
+ TrackStatusIds = x.TrackStatusIds.Split(',').Select(int.Parse).ToHashSet(),
+ ReturnTimeSpan = x.ReturnTimeSpan,
+ NotifyUsers = x.NotifyUsers
+ }).ToList();
+ }
+
+ public static List From(List entities)
+ {
+ return entities.Select(From).ToList();
+ }
+
+ public static ReturnWarningRuleItemBO From(ReturnWarningRuleItemEntity entity)
+ {
+ return new ReturnWarningRuleItemBO
+ {
+ Id = entity.Id,
+ WarningId = entity.WarningId,
+ TrackStatusIds = entity.TrackStatusIds.Split(',').Select(int.Parse).ToHashSet(),
+ ReturnTimeSpan = entity.ReturnTimeSpan,
+ NotifyUsers = TextJsonHelper.Deserialize>(entity.NotifyUsers)!
+ };
+ }
+
+ public ReturnWarningRuleItemEntity ToEntity()
+ {
+ return new ReturnWarningRuleItemEntity(
+ Id,
+ WarningId,
+ string.Join(',', TrackStatusIds),
+ ReturnTimeSpan,
+ TextJsonHelper.Serialize(NotifyUsers)!
+ );
+ }
+
+ public static List ToEntities(List bos)
+ {
+ return bos.Select(x => x.ToEntity()).ToList();
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Model/TransportWarningSceneBO.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/TransportWarningSceneBO.cs
new file mode 100644
index 00000000..09452eb5
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/TransportWarningSceneBO.cs
@@ -0,0 +1,161 @@
+using SJZY.Track.Application.Contract.Dtos.Warning.Transport;
+using SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
+using SJZY.Track.Domain.Aggregates.OrderAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Model;
+
+public sealed class TransportWarningSceneBO
+{
+ ///
+ /// 场景唯一id (传0视为新增)
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// 预警规则主体id
+ ///
+ public int WarningId { get; set; }
+
+ ///
+ /// 是否中转(单一)
+ ///
+ public bool? IsTransit { get; set; }
+
+ ///
+ /// 货物类型(多个,分割)
+ ///
+ public string? CargoType { get; set; }
+
+ ///
+ /// 起运港口(多个,分割)
+ ///
+ public string? LeavePort { get; set; }
+
+ ///
+ /// 产品编码(多个,分割)
+ ///
+ public string? ProductCode { get; set; }
+
+ ///
+ /// 月份(多个/分割)
+ ///
+ public string? Months { get; set; }
+
+ ///
+ /// 区域Id(单一)
+ ///
+ public int? AreaId { get; set; }
+
+
+ public bool CanHitScene(OrderEntity order, List? ruleAreas)
+ {
+ // 是否中转
+ if (IsTransit != null && IsTransit != order.IsTransit) return false;
+
+ // 货物类型
+ if (!string.IsNullOrWhiteSpace(CargoType) && order.CargoType != CargoType) return false;
+
+ // 启运港口
+ if (!string.IsNullOrWhiteSpace(LeavePort) && order.LeavePort != LeavePort) return false;
+
+ // 产品编码
+ if (!string.IsNullOrWhiteSpace(ProductCode) && order.ProductCode != ProductCode) return false;
+
+ // 月份
+ if (!string.IsNullOrWhiteSpace(Months))
+ {
+ var months = string.IsNullOrEmpty(Months)
+ ? new HashSet()
+ : Months.Split('/').Select(int.Parse).ToHashSet();
+ // 订单创建时间月份
+ var orderCreateTimeMonth = order.CreateTime.Month;
+ if (!months.Contains(orderCreateTimeMonth)) return false;
+ }
+
+ // 区域
+ if (ruleAreas != null && ruleAreas.Count > 0)
+ {
+ // 使用订单到达国家的二字码匹配区域
+ var areas = ruleAreas.Where(area => order.ArrivalCountry == area.CountryCode).ToList();
+ foreach (var area in areas)
+ {
+ // 邮编是否在关注的范围内?
+ if (!string.IsNullOrWhiteSpace(area.LeftPostcode) && !string.IsNullOrWhiteSpace(area.RightPostcode))
+ {
+ // tips: 参考小包的邮编匹配,字典序
+ if (string.CompareOrdinal(order.ArrivalPostCode, area.LeftPostcode) < 0 ||
+ string.CompareOrdinal(order.ArrivalPostCode, area.RightPostcode) > 0)
+ return false;
+ }
+
+ // 城市是否匹配?
+ if (!string.IsNullOrWhiteSpace(area.City) && order.ArrivalCity != area.City) return false;
+
+ // 省份是否匹配?
+ if (!string.IsNullOrWhiteSpace(area.Province) && order.ArrivalProvince != area.Province) return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ public static TransportWarningSceneEntity ToEntity(TransportWarningSceneBO bo)
+ {
+ return new TransportWarningSceneEntity(
+ bo.Id,
+ bo.WarningId,
+ bo.CargoType,
+ bo.Months,
+ bo.AreaId,
+ bo.IsTransit,
+ bo.LeavePort,
+ bo.ProductCode
+ );
+ }
+
+ public TransportWarningSceneEntity ToEntity()
+ {
+ return new TransportWarningSceneEntity(
+ Id,
+ WarningId,
+ CargoType,
+ Months,
+ AreaId,
+ IsTransit,
+ LeavePort,
+ ProductCode
+ );
+ }
+
+ public static TransportWarningSceneBO From(TransportWarningSceneEntity entity)
+ {
+ return new TransportWarningSceneBO
+ {
+ Id = entity.Id,
+ WarningId = entity.WarningId,
+ CargoType = entity.CargoType,
+ Months = entity.Months,
+ AreaId = entity.AreaId,
+ IsTransit = entity.IsTransit,
+ LeavePort = entity.LeavePort,
+ ProductCode = entity.ProductCode
+ };
+ }
+
+ public static TransportWarningSceneBO From(UpsertTransportWarningSceneInput input)
+ {
+ return new TransportWarningSceneBO
+ {
+ Id = input.Id,
+ WarningId = input.WarningId,
+ CargoType = input.CargoType,
+ Months = input.Months,
+ AreaId = input.AreaId,
+ IsTransit = input.IsTransit,
+ LeavePort = input.LeavePort,
+ ProductCode = input.ProductCode
+ };
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Model/TransportWarningSceneRuleItemBO.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/TransportWarningSceneRuleItemBO.cs
new file mode 100644
index 00000000..5ed000ac
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Model/TransportWarningSceneRuleItemBO.cs
@@ -0,0 +1,123 @@
+using SJZY.Track.Application.Contract.Dtos.Warning;
+using SJZY.Track.Application.Contract.Dtos.Warning.Transport;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+using SJZY.Track.Domain.Extensions;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Model;
+
+///
+/// 处理运输时效规则项目的业务模型
+/// 可以通过入参/持久化模型转化
+///
+public sealed class TransportWarningSceneRuleItemBO
+{
+ ///
+ /// 规则项目id(传0视为新增)
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// 预警规主体id
+ ///
+ public int WarningId { get; set; }
+
+ ///
+ /// 运输预警场景id
+ ///
+ public int SceneId { get; set; }
+
+ ///
+ /// 起始轨迹状态Id
+ ///
+ public int StartTrackStatusId { get; set; }
+
+ ///
+ /// 截止轨迹状态Id
+ ///
+ public int EndTrackStatusId { get; set; }
+
+ ///
+ /// 时效 (单位h)
+ ///
+ public float TransportTimeSpan { get; set; }
+
+ ///
+ /// 起始轨迹生成预警时间 (单位h)
+ ///
+ public float StartTrackWarningTimeSpan { get; set; }
+
+ ///
+ /// 通知对象用户集合
+ ///
+ public List NotifyUsers { get; set; }
+
+ public static List From(EditTransportWarningSceneRuleItemInput input)
+ {
+ var warningId = input.WarningId;
+ var sceneId = input.SceneId;
+ return input.Items.Select(x => new TransportWarningSceneRuleItemBO
+ {
+ Id = x.Id,
+ WarningId = warningId,
+ SceneId = sceneId,
+ StartTrackStatusId = x.StartTrackStatusId,
+ EndTrackStatusId = x.EndTrackStatusId,
+ TransportTimeSpan = x.TransportTimeSpan,
+ StartTrackWarningTimeSpan = x.StartTrackWarningTimeSpan,
+ NotifyUsers = x.NotifyUsers
+ })
+ .ToList();
+ }
+
+ public static TransportWarningSceneRuleItemBO From(TransportWarningSceneRuleItemEntity entity)
+ {
+ return new TransportWarningSceneRuleItemBO
+ {
+ Id = entity.Id,
+ WarningId = entity.WarningId,
+ SceneId = entity.TransportWarningSceneId,
+ StartTrackStatusId = entity.StartTrackStatusId,
+ EndTrackStatusId = entity.EndTrackStatusId,
+ TransportTimeSpan = entity.TransportTimeSpan,
+ StartTrackWarningTimeSpan = entity.StartTrackWarningTimeSpan,
+ NotifyUsers = TextJsonHelper.Deserialize>(entity.NotifyUsers)!
+ };
+ }
+
+ public static List From(List entities)
+ {
+ return entities.Select(From).ToList();
+ }
+
+ public TransportWarningSceneRuleItemEntity ToEntity()
+ {
+ return new TransportWarningSceneRuleItemEntity(
+ Id,
+ WarningId,
+ SceneId,
+ StartTrackStatusId,
+ EndTrackStatusId,
+ TransportTimeSpan,
+ StartTrackWarningTimeSpan,
+ TextJsonHelper.Serialize(NotifyUsers)!
+ );
+ }
+
+ public static List ToEntities(List bos)
+ {
+ return bos.Select(x=>x.ToEntity()).ToList();
+ }
+
+ public bool CanHitRule(int trackStatusId, HashSet trackStatusIds)
+ {
+ return trackStatusId == StartTrackStatusId //命中起始轨迹状态
+ && !trackStatusIds.Contains(EndTrackStatusId); //缺失截止轨迹状态
+ }
+
+ // 重新命中,用于规则扫描
+ public bool CanReHit(HashSet trackStatusIds)
+ {
+ return trackStatusIds.Contains(StartTrackStatusId) //存在起始
+ && !trackStatusIds.Contains(EndTrackStatusId); //不存在截止
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs
new file mode 100644
index 00000000..0de719dd
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/ReturnWarningHandler.cs
@@ -0,0 +1,162 @@
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Application.Services.Warning.Handlers.Warning;
+using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers;
+
+public sealed class ReturnWarningHandler : IReturnWarningHandler
+{
+ private readonly IWarningRuleRepository _warningRuleRepository;
+
+ public ReturnWarningHandler(IWarningRuleRepository warningRuleRepository)
+ {
+ _warningRuleRepository = warningRuleRepository;
+ }
+
+ public Task TrackUpdatedOrDeletedHandleAsync(List updateOrDeleteSignals)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task ReceiveTrackPushRecordHandleAsync(TrackPushRecordIndex record)
+ {
+ throw new NotImplementedException();
+ }
+
+
+ public Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task PushConfigChangedHandleAsync(TrackPushConfigEntity pushConfig, TrackPushContentConfigEntity pushContentConfig)
+ {
+ throw new NotImplementedException();
+ }
+
+
+ #region todo: 规则项目变更
+
+ public async Task HandleEditAsync(WarningRuleEntity rule, List postRuleItems)
+ {
+ var addRuleItems = postRuleItems.Where(x => x.Id == 0).ToList();
+ // 1.找到之前的配置项目
+ var entities = await _warningRuleRepository.GetReturnRuleItemsAsync(rule.Id);
+ var oldRuleItems = ReturnWarningRuleItemBO.From(entities);
+ // 1.1之前的配置数量为0,做只新增处理
+ if (oldRuleItems.Count == 0)
+ {
+ if (addRuleItems.Count != 0)
+ await OnlyAddHandleAsync(rule, addRuleItems);
+
+ return;
+ }
+
+ // 1.2之前的配置数量不为0,提交的数量为0,做只删除处理
+ if (oldRuleItems.Count != 0 && postRuleItems.Count == 0)
+ {
+ await OnlyDeleteHandleAsync(rule, oldRuleItems);
+ return;
+ }
+
+ // 关心规则修改/删除
+ var updateRuleItems = new List();
+ var deleteRuleItems = new List();
+
+ // 2.差异化比较
+ // 构建配置id字段
+ var oldDict = oldRuleItems.ToDictionary(x => x.Id);
+ var postDict = postRuleItems
+ .Where(x => x.Id != 0) //tips:忽略新增的规则条目
+ .ToDictionary(x => x.Id);
+ var ruleItemIds = oldDict.Keys.Concat(postDict.Keys).ToHashSet();
+ foreach (var ruleItemId in ruleItemIds)
+ {
+ var oldRule = oldDict.GetValueOrDefault(ruleItemId);
+ var postRule = postDict.GetValueOrDefault(ruleItemId);
+ if (oldRule != null && postRule != null)
+ {
+ //规则属性变更,(状态减少,时效变更)
+ if (CanNeedFollow(oldRule, postRule))
+ updateRuleItems.Add(postRule);
+ continue;
+ }
+
+ //规则条目被删除
+ if (oldRule != null && postRule == null)
+ deleteRuleItems.Add(oldRule);
+ }
+
+ // 3.处理变更
+ await HandleRuleItemsChangeAsync(rule, addRuleItems, updateRuleItems, deleteRuleItems);
+ }
+
+ private async Task OnlyAddHandleAsync(WarningRuleEntity rule, List bos)
+ {
+ var entities = ReturnWarningRuleItemBO.ToEntities(bos);
+ await _warningRuleRepository.BulkInsertReturnRuleItemsAsync(entities);
+ // 更新规则主体版本号
+ await _warningRuleRepository.UpdateVersionAsync(rule);
+ }
+
+ private async Task OnlyDeleteHandleAsync(WarningRuleEntity rule, List bos)
+ {
+ var ruleItemIds = bos.Select(x => x.Id).ToHashSet();
+ await _warningRuleRepository.DeleteReturnRuleItemsAsync(ruleItemIds);
+
+ // 更新规则主体版本号
+ await _warningRuleRepository.UpdateVersionAsync(rule);
+
+ // todo:暂时不处理后续逻辑
+ return;
+ }
+
+ private async Task HandleRuleItemsChangeAsync(WarningRuleEntity rule,
+ List addRuleItems,
+ List updateRuleItems,
+ List deleteRuleItems)
+ {
+ // 新增/修改/删除 实体,稍后做处理
+ var addEntities = ReturnWarningRuleItemBO.ToEntities(addRuleItems);
+ var updateEntities = ReturnWarningRuleItemBO.ToEntities(updateRuleItems);
+ var deleteRuleItemIds = deleteRuleItems.Select(x => x.Id).ToHashSet();
+ await _warningRuleRepository.BulkInsertReturnRuleItemsAsync(addEntities);
+ await _warningRuleRepository.BulkUpdateReturnRuleItemsAsync(updateEntities);
+ await _warningRuleRepository.DeleteReturnRuleItemsAsync(deleteRuleItemIds);
+
+ // todo:暂时不启用后续规则
+ return;
+ }
+
+ private static bool CanNeedFollow(ReturnWarningRuleItemBO oldRule, ReturnWarningRuleItemBO postRule)
+ {
+ // 时效发生更改
+ if (Math.Abs(oldRule.ReturnTimeSpan - postRule.ReturnTimeSpan) > 1.0)
+ return true;
+
+ // 关注的轨迹状态减少
+ var oldStatusIds = oldRule.TrackStatusIds;
+ var postStatusIds = postRule.TrackStatusIds;
+ foreach (var statusId in oldStatusIds)
+ if (!postStatusIds.Contains(statusId))
+ return true;
+
+ return false;
+ }
+
+ #endregion
+
+
+ public List DiffFilterReturnWarningRuleItems(WarningRuleEntity rule, List postRuleItems)
+ {
+ throw new NotImplementedException();
+ }
+
+ public List FilterAndHandleNeedNotifyTask(List notifyTasks)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs
new file mode 100644
index 00000000..49ba57e2
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/TransportWarningHandler.cs
@@ -0,0 +1,418 @@
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Application.Services.Warning.Handlers.Warning;
+using SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
+using SJZY.Track.Domain.Aggregates.OrderAggregate;
+using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+using SJZY.Track.Domain.Enums;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers;
+
+public class TransportWarningHandler : ITransportWarningHandler
+{
+ private readonly IKpiAreaRepository _kpiAreaRepository;
+ private readonly IOrderRepository _orderRepository;
+ private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
+ private readonly IWarningRuleRepository _warningRuleRepository;
+ private readonly IWarningTaskRepository _warningTaskRepository;
+ private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
+
+ public TransportWarningHandler(IWarningTaskRepository warningTaskRepository, IWarningDetailsEsRepository warningDetailsEsRepository, IWarningRuleRepository warningRuleRepository, IOrderRepository orderRepository, ITrackDetailsEsRepository trackDetailsEsRepository, IKpiAreaRepository kpiAreaRepository)
+ {
+ _warningTaskRepository = warningTaskRepository;
+ _warningDetailsEsRepository = warningDetailsEsRepository;
+ _warningRuleRepository = warningRuleRepository;
+ _orderRepository = orderRepository;
+ _trackDetailsEsRepository = trackDetailsEsRepository;
+ _kpiAreaRepository = kpiAreaRepository;
+ }
+
+ #region 预警信号处理
+
+ public Task TrackDeletedHandleAsync(List deletedSignals)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task TrackAddedOrUpdatedHandleAsync(List addOrDeleteSignals)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+
+ public Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule)
+ {
+ throw new NotImplementedException();
+ }
+
+
+ #region todo: 规则场景变更
+
+ public async Task HandleSceneChangedAsync(WarningRuleEntity rule, TransportWarningSceneBO oldScene, TransportWarningSceneBO postScene)
+ {
+ if (!CanSceneChange(oldScene, postScene)) return;
+
+ // todo:暂时不做后续处理
+ return;
+ }
+
+ private bool CanSceneChange(TransportWarningSceneBO oldScene, TransportWarningSceneBO postScene)
+ {
+ return oldScene.CargoType != postScene.CargoType || //多个 普货,危险品
+ oldScene.Months != postScene.Months || //多个 约束提交的月份组从小到大 1/3/4,不能出现 4/1/3这种 (如果出现则SequenceEqual)
+ oldScene.AreaId != postScene.AreaId || // 单一,area1
+ oldScene.IsTransit != postScene.IsTransit || //单一,true
+ oldScene.LeavePort != postScene.LeavePort || //多个
+ oldScene.ProductCode != postScene.ProductCode; //多个
+ }
+
+ #endregion
+
+
+ #region todo: 规则项目变更
+
+ public async Task HandleEditAsync(WarningRuleEntity rule, TransportWarningSceneEntity scene, List postRuleItems)
+ {
+ var addRuleItems = postRuleItems.Where(x => x.Id == 0).ToList();
+
+ // 1.找到之前的配置项目
+ var entities = await _warningRuleRepository.GetTransportSceneRuleItemsAsync(rule.Id, scene.Id);
+ var oldRuleItems = TransportWarningSceneRuleItemBO.From(entities);
+ // 1.1之前的配置数量为0,做只新增处理
+ if (oldRuleItems.Count == 0)
+ {
+ if (addRuleItems.Count != 0)
+ await OnlyAddHandleAsync(rule, scene, addRuleItems);
+
+ return;
+ }
+
+ // 1.2之前的配置数量不为0,提交的数量为0,做只删除处理
+ if (oldRuleItems.Count != 0 && postRuleItems.Count == 0)
+ {
+ await OnlyDeleteHandleAsync(rule, scene, oldRuleItems);
+ return;
+ }
+
+ // 可能同时存在 新增/修改/删除
+ var updateRuleItems = new List();
+ var deleteRuleItems = new List();
+
+ // 2.差异化比较
+ // 2.1构建配置id字段
+ var oldRuleIdDict = oldRuleItems.ToDictionary(x => x.Id);
+ var postRuleIdDict = postRuleItems
+ .Except(addRuleItems) //tips:忽略新增的规则条目
+ .ToDictionary(x => x.Id);
+ var ruleItemIds = oldRuleIdDict.Keys.Concat(postRuleIdDict.Keys).ToHashSet();
+ // 2.2比较
+ foreach (var ruleItemId in ruleItemIds)
+ {
+ var oldRule = oldRuleIdDict.GetValueOrDefault(ruleItemId);
+ var postRule = postRuleIdDict.GetValueOrDefault(ruleItemId);
+ if (oldRule != null && postRule != null)
+ {
+ //规则属性变更,(起/止状态,时效变更)
+ if (CanNeedFollow(oldRule, postRule))
+ updateRuleItems.Add(postRule); //更新 关注新的配置
+
+ continue;
+ }
+
+ //规则条目被删除
+ if (oldRule != null && postRule == null)
+ deleteRuleItems.Add(oldRule); //删除 关注旧配置
+ }
+
+ // 3.处理变更
+ await HandleRuleItemsChangeAsync(rule, scene, addRuleItems, updateRuleItems, deleteRuleItems);
+ }
+
+ private async Task OnlyAddHandleAsync(WarningRuleEntity rule, TransportWarningSceneEntity scene, List bos)
+ {
+ var entities = TransportWarningSceneRuleItemBO.ToEntities(bos);
+ await _warningRuleRepository.BulkInsertTransportSceneRuleItemsAsync(entities);
+ // 更新规则主体版本号
+ await _warningRuleRepository.UpdateVersionAsync(rule);
+ }
+
+ private async Task OnlyDeleteHandleAsync(WarningRuleEntity rule, TransportWarningSceneEntity scene, List bos)
+ {
+ var ruleItemIds = bos.Select(x => x.Id).ToHashSet();
+ await _warningRuleRepository.DeleteTransportSceneRuleItemsAsync(ruleItemIds);
+
+ // 更新规则主体版本号
+ await _warningRuleRepository.UpdateVersionAsync(rule);
+
+ // todo:暂时不处理后续逻辑
+ return;
+ // 处理轨迹删除
+ await HandleDeleteAsync(ruleItemIds);
+ }
+
+ private async Task HandleRuleItemsChangeAsync(
+ WarningRuleEntity rule,
+ TransportWarningSceneEntity scene,
+ List addRuleItems,
+ List updateRuleItems,
+ List deleteRuleItems
+ )
+ {
+ // 新增/修改/删除 实体,稍后做处理
+ var addEntities = TransportWarningSceneRuleItemBO.ToEntities(addRuleItems);
+ var updateEntities = TransportWarningSceneRuleItemBO.ToEntities(updateRuleItems);
+ var deleteRuleItemIds = deleteRuleItems.Select(x => x.Id).ToHashSet();
+ await _warningRuleRepository.BulkInsertTransportSceneRuleItemsAsync(addEntities);
+ await _warningRuleRepository.BulkUpdateTransportSceneRuleItemsAsync(updateEntities);
+ await _warningRuleRepository.DeleteTransportSceneRuleItemsAsync(deleteRuleItemIds);
+
+ // todo:暂时不启用后续规则
+ return;
+ // 1.查询变更配置相关的预警生成任务(未关闭的)
+ var updateRuleItemIds = updateRuleItems.Select(x => x.Id).ToHashSet();
+ var generateTasks = await _warningTaskRepository.GetTransportWarningDetailsGenerateTaskAsync(x =>
+ !x.IsClosed
+ && x.WarningId == scene.WarningId
+ && updateRuleItemIds.Contains(x.WarningSceneRuleItemId)
+ );
+
+ // 2.查询变更配置相关的预警通知任务(未关闭的)
+ var warningNotifyTasks = await _warningTaskRepository.GetWarningNotifyTaskAsync(x =>
+ !x.IsClosed
+ && x.WarningId == rule.Id
+ && x.WarningType == WarningRuleType.运输时效预警.GetHashCode()
+ && updateRuleItemIds.Contains(x.WarningRuleId)
+ );
+
+ // 3.查询变更配置相关的预警明细(即将超时/已超时)
+ var warningDetails = await _warningDetailsEsRepository.GetTransportWarningDetailsAsync(
+ updateRuleItemIds,
+ new HashSet(2)
+ {
+ TransportWarningStatus.即将超时.GetHashCode(),
+ TransportWarningStatus.已超时.GetHashCode()
+ }
+ );
+
+ // 构建处理快
+ var handleBlocks = new List(generateTasks.Count + warningNotifyTasks.Count + warningDetails.Count);
+ // 使用【预警明细】【预警生成任务】【预警通知任务】填充处理块
+ handleBlocks.AddRange(generateTasks.Select(x => new HandleBlock(x.OrderId, x.WarningSceneRuleItemId, x)));
+ handleBlocks.AddRange(warningNotifyTasks.Select(x => new HandleBlock(x.OrderId, x.WarningRuleId, x)));
+ handleBlocks.AddRange(warningDetails.Select(x => new HandleBlock(x.OrderId, x.WarningSceneRuleItemId, x)));
+
+ // tips:无需在通过预警通知任务反找订单,因为产生预警通知任务时预警明细已经存在!
+ // 查询订单
+ var orderIds = handleBlocks.Select(x => x.OrderId).ToHashSet();
+ var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id));
+ orderIds = orders.Select(x => x.Id).ToHashSet();
+ // 查询这些订单相关的轨迹
+ var allOrderTracks = await _trackDetailsEsRepository.GetListAsync(orderIds.ToArray());
+ var orderTrackStatusIdsDict = allOrderTracks.GroupBy(x => x.OrderId)
+ .ToDictionary(x => x.Key, y => y.ToList());
+
+ // 3.检查是否重新命中规则
+ var ruleArea = scene.AreaId.HasValue ? await _kpiAreaRepository.GetFirstAsync(x => x.Id == scene.AreaId.Value) : null;
+ var updateRuleItemIdDict = updateRuleItems.ToDictionary(x => x.Id);
+ foreach (var group in handleBlocks.GroupBy(x => (x.OrderId, x.RuleItemId)))
+ {
+ var key = group.Key;
+ var ruleItem = updateRuleItemIdDict[key.RuleItemId];
+ var orderTracks = orderTrackStatusIdsDict[key.OrderId];
+ var earliestTrack = orderTracks
+ .Where(x => x.TrackStatusId == ruleItem.StartTrackStatusId)
+ .OrderBy(x => x.TrackTime)
+ .First();
+ var orderStatusIds = orderTracks
+ .Select(x => x.TrackStatusId)
+ .ToHashSet();
+
+ var reHit = ruleItem.CanReHit(orderStatusIds); //存在起始,不存在截止,视为命中
+ foreach (var block in group)
+ {
+ block.ReHitRule = reHit;
+ if (reHit && block.Type == HandleType.Detail) //重新命中的轨迹,需要更新预警信息中的规则描述,以及轨迹信息(起始)
+ {
+ // 配置相关信息
+ block.Detail.WarningName = rule.Name;
+ block.Detail.WarningRuleDescription = block.Detail.GetWarningRuleDescription(scene, ruleItem.ToEntity(), ruleArea);
+ block.Detail.TransportTimeSpan = ruleItem.TransportTimeSpan;
+ block.Detail.StartTrackWarningTimeSpan = ruleItem.StartTrackWarningTimeSpan;
+ // 起始轨迹相关信息
+ block.Detail.StartTrackStatusId = earliestTrack.TrackStatusId;
+ block.Detail.StartTrackStatus = earliestTrack.TrackStatus;
+ block.Detail.StartTrackContentId = earliestTrack.TrackContentId;
+ block.Detail.StartTrackContent = earliestTrack.TrackContent;
+ block.Detail.StartTrackTime = earliestTrack.TrackTime; //用于更新累计运输时间
+ block.Detail.StartTrackTimeZone = earliestTrack.TrackTimeZone;
+ continue;
+ }
+
+ // tips:更改后直接引发任务进行,等待下一轮任务扫描就会注意到
+ if (reHit && block.Type == HandleType.GenerateTask) //重新命中的轨迹,需要更新预警生成任务
+ {
+ // 更新生成任务当中的相关信息
+ block.GenerateTask.StartTrackStatusId = earliestTrack.TrackStatusId;
+ block.GenerateTask.EndTrackStatusId = ruleItem.EndTrackStatusId;
+ block.GenerateTask.StartTrackTime = earliestTrack.TrackTime;
+ block.GenerateTask.StartTrackTimeZone = earliestTrack.TrackTimeZone;
+ block.GenerateTask.StartTrackWarningTimeSpan = ruleItem.StartTrackWarningTimeSpan;
+ block.GenerateTask.PlanExecutionTime = earliestTrack.TrackTime.AddHours(ruleItem.StartTrackWarningTimeSpan);
+ }
+ }
+ }
+
+ // 重新命中规则的处理块
+ var reHitRuleBlocks = handleBlocks.Where(x => x.ReHitRule).ToList();
+
+ // 3.1 更新预警明细(重新命中规则)
+ var updateWarningDetails = reHitRuleBlocks
+ .Where(x => x.Type == HandleType.Detail)
+ .Select(x => x.Detail)
+ .ToList();
+ await _warningDetailsEsRepository.BulkUpdateTransportWarningDetailsAsync(updateWarningDetails);
+
+ // 3.2 更新预警生成任务(重新命中规则)
+ var updateGenerateTasks = reHitRuleBlocks
+ .Where(x => x.Type == HandleType.GenerateTask)
+ .Select(x => x.GenerateTask)
+ .ToList();
+ await _warningTaskRepository.BulkUpdateTransportWarningDetailsGenerateTaskAsync(updateGenerateTasks);
+
+ // 3.3 处理需要关闭的【预警明细】【预警生成任务】【预警通知任务】(未命中规则)
+ var typeIdsDict = handleBlocks
+ .Except(reHitRuleBlocks)
+ .GroupBy(x => x.Type)
+ .ToDictionary(x => x.Key, y =>
+ {
+ return y.Key switch
+ {
+ HandleType.Detail => y.Select(x => x.Detail.Id).ToHashSet(),
+ HandleType.GenerateTask => y.Select(x => x.GenerateTask.Id.ToString()).ToHashSet(),
+ HandleType.NotifyTask => y.Select(x => x.NotifyTask.Id.ToString()).ToHashSet(),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ });
+
+ // 4.处理删除规则的相关联的【预警明细】【预警生成任务】【预警通知任务】
+ // 预警信息状态修改为已关闭(即将超时/已超时)
+ var closeDetailIds = typeIdsDict.GetValueOrDefault(HandleType.Detail, new HashSet());
+ await _warningDetailsEsRepository.BulkCloseTransportWarningDetailsAsync(closeDetailIds);
+
+ // 关闭相关的预警生成任务(未关闭的)
+ var closeGenerateTaskIds = typeIdsDict.GetValueOrDefault(HandleType.GenerateTask, new HashSet());
+ await _warningTaskRepository.CloseTransportWarningDetailsGenerateTaskAsync(x =>
+ !x.IsClosed
+ && (
+ closeGenerateTaskIds.Contains(x.Id.ToString())
+ || (x.WarningId == rule.Id && deleteRuleItemIds.Contains(x.WarningSceneRuleItemId))
+ )
+ );
+
+ // 关闭关联的预警通知任务(未关闭的)
+ var closeNotifyTaskIds = typeIdsDict.GetValueOrDefault(HandleType.NotifyTask, new HashSet());
+ await _warningTaskRepository.CloseWarningNotifyTaskAsync(x =>
+ !x.IsClosed
+ && (
+ closeNotifyTaskIds.Contains(x.Id.ToString())
+ || (x.WarningId == rule.Id
+ && x.WarningType == WarningRuleType.运输时效预警.GetHashCode()
+ && deleteRuleItemIds.Contains(x.WarningRuleId))
+ ));
+ }
+
+ private async Task HandleDeleteAsync(HashSet deleteRuleItemIds)
+ {
+ // 处理删除规则的相关联的【预警明细】【预警生成任务】【预警通知任务】
+ // 预警信息状态修改为已关闭(即将超时/已超时)
+ await _warningDetailsEsRepository.BulkCloseTransportWarningDetailsAsync(deleteRuleItemIds);
+
+ // 关闭相关的预警生成任务(未关闭的)
+ await _warningTaskRepository.CloseTransportWarningDetailsGenerateTaskAsync(x =>
+ !x.IsClosed
+ && deleteRuleItemIds.Contains(x.WarningSceneRuleItemId)
+ );
+
+ // 关闭关联的预警通知任务(未关闭的)
+ await _warningTaskRepository.CloseWarningNotifyTaskAsync(x =>
+ !x.IsClosed
+ && x.WarningType == WarningRuleType.运输时效预警.GetHashCode()
+ && deleteRuleItemIds.Contains(x.WarningRuleId)
+ );
+ }
+
+ private static bool CanNeedFollow(TransportWarningSceneRuleItemBO oldRule, TransportWarningSceneRuleItemBO postRule)
+ {
+ if (oldRule.StartTrackStatusId != postRule.StartTrackStatusId)
+ return true;
+
+ if (oldRule.EndTrackStatusId != postRule.EndTrackStatusId)
+ return true;
+
+ if (Math.Abs(oldRule.TransportTimeSpan - postRule.TransportTimeSpan) > 1.0f)
+ return true;
+
+ if (Math.Abs(oldRule.StartTrackWarningTimeSpan - postRule.StartTrackWarningTimeSpan) > 1.0f)
+ return true;
+
+ return false;
+ }
+
+ private enum HandleType
+ {
+ Detail = 0,
+ GenerateTask = 1,
+ NotifyTask = 2
+ }
+
+ private sealed class HandleBlock
+ {
+ public int OrderId { get; }
+ public int RuleItemId { get; }
+ public HandleType Type { get; }
+
+#nullable disable
+ public TransportWarningDetailsIndex Detail { get; }
+ public TransportWarningDetailsGenerateTaskEntity GenerateTask { get; }
+ public WarningNotifyTaskEntity NotifyTask { get; }
+ public bool ReHitRule { get; set; } //是否重新命中规则条目
+
+ private HandleBlock(int orderId, int ruleItemId)
+ {
+ OrderId = orderId;
+ RuleItemId = ruleItemId;
+ }
+
+ public HandleBlock(int orderId, int ruleItemId, TransportWarningDetailsIndex detail)
+ : this(orderId, ruleItemId)
+ {
+ Type = HandleType.Detail;
+ Detail = detail;
+ }
+
+ public HandleBlock(int orderId, int ruleItemId, TransportWarningDetailsGenerateTaskEntity task)
+ : this(orderId, ruleItemId)
+ {
+ Type = HandleType.GenerateTask;
+ GenerateTask = task;
+ }
+
+ public HandleBlock(int orderId, int ruleItemId, WarningNotifyTaskEntity task)
+ : this(orderId, ruleItemId)
+ {
+ Type = HandleType.NotifyTask;
+ NotifyTask = task;
+ }
+ }
+
+ #endregion
+
+ public List FilterAndHandleNeedNotifyTask(List notifyTasks)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/ICompleteWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/ICompleteWarningHandler.cs
new file mode 100644
index 00000000..3249df10
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/ICompleteWarningHandler.cs
@@ -0,0 +1,24 @@
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Warning;
+
+public interface ICompleteWarningHandler : ITransientDependency
+{
+ // 处理轨迹 删除 todo:未实现,用于处理信号,需要支持批量处理
+ Task TrackDeletedHandleAsync(List deletedSignals);
+
+ // 处理轨迹 新增 todo:未实现,用于处理信号,需要支持批量处理
+ Task TrackAddedHandleAsync(List addedSignals);
+
+ // 完整预警主体禁用 todo:未实现
+ Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule);
+
+ // 处理完整预警规则项变更
+ Task HandleEditAsync(WarningRuleEntity rule, List postRuleItems);
+
+ // 预警通知任务可行性过滤 todo:未实现
+ List FilterAndHandleNeedNotifyTask(List notifyTasks);
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/IReturnWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/IReturnWarningHandler.cs
new file mode 100644
index 00000000..7faaf421
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/IReturnWarningHandler.cs
@@ -0,0 +1,28 @@
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Warning;
+
+public interface IReturnWarningHandler : ITransientDependency
+{
+ // 处理轨迹 修改/删除 todo:未实现,用于处理信号,需要支持批量处理
+ Task TrackUpdatedOrDeletedHandleAsync(List updateOrDeleteSignals);
+
+ // 收到轨迹推送记录(接口通回调)(人工介入/重试 阶段的回传) todo:未实现
+ Task ReceiveTrackPushRecordHandleAsync(TrackPushRecordIndex record);
+
+ // 回传预警主体禁用 todo:未实现
+ Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule);
+
+ // 处理推送映射配置变更 todo:未实现
+ Task PushConfigChangedHandleAsync(TrackPushConfigEntity pushConfig, TrackPushContentConfigEntity pushContentConfig);
+
+ // 处理编辑回传预警规则项
+ Task HandleEditAsync(WarningRuleEntity rule, List postRuleItems);
+
+ // 预警通知任务可行性过滤 todo:未实现
+ List FilterAndHandleNeedNotifyTask(List notifyTasks);
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/ITransportWarningHandler.cs b/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/ITransportWarningHandler.cs
new file mode 100644
index 00000000..7982f919
--- /dev/null
+++ b/src/SJZY.Track.Application/Services/Warning/Handlers/Warning/ITransportWarningHandler.cs
@@ -0,0 +1,31 @@
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.Services.Warning.Handlers.Warning;
+
+///
+/// todo:提供业务模型的转化方法
+///
+public interface ITransportWarningHandler : ITransientDependency
+{
+ // 处理轨迹 删除 todo:用于处理信号,需要支持批量处理
+ Task TrackDeletedHandleAsync(List deletedSignals);
+
+ // 处理轨迹 新增/修改 todo:用于处理信号,需要支持批量处理
+ Task TrackAddedOrUpdatedHandleAsync(List addOrDeleteSignals);
+
+ // 运输预警主体禁用 todo:未实现
+ Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule);
+
+ // 运输预警场景变更
+ Task HandleSceneChangedAsync(WarningRuleEntity rule, TransportWarningSceneBO oldScene, TransportWarningSceneBO postScene);
+
+ // 处理配置项列表保存
+ Task HandleEditAsync(WarningRuleEntity rule, TransportWarningSceneEntity scene, List bos);
+
+ // 预警通知可行性筛选 todo:未实现
+ List FilterAndHandleNeedNotifyTask(List notifyTasks);
+}
diff --git a/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs b/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs
index a687a53a..3b206961 100644
--- a/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/ReturnWarningService.cs
@@ -1,4 +1,13 @@
+using SJZY.Expand.ABP.Core.PublicMethords;
+using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Return;
+using SJZY.Track.Application.Helpers;
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Application.Services.Warning.Handlers.Warning;
+using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Dtos.Warning;
+using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Application.Services.Warning;
@@ -9,35 +18,17 @@ namespace SJZY.Track.Application.Services.Warning;
[Route("Warning/Return")]
public class ReturnWarningService : ApplicationService
{
- ///
- /// 编辑回传预警规则列表
- ///
- ///
- ///
- [HttpPost("EditReturnWarningRuleItem")]
- public Task EditReturnWarningRuleItem(EditReturnWarningRuleItemInput input)
- {
- return Task.FromResult(new UnifyResultDto());
- }
+ private readonly IReturnWarningHandler _returnWarningHandler;
+ private readonly IWarningRuleRepository _warningRuleRepository;
+ private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
+ private readonly ITrackStatusRepository _trackStatusRepository;
- ///
- /// 分页获取回传预警明细
- ///
- ///
- ///
- [HttpPost("GetPageReturnWarningDetails")]
- public Task> GetPageReturnWarningDetails(GetPageReturnWarningDetailsInput input)
+ public ReturnWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, IReturnWarningHandler returnWarningHandler, ITrackStatusRepository trackStatusRepository)
{
- return Task.FromResult(new UnifyPageResultDto());
- }
-
- ///
- /// 获取回传报文日志
- ///
- [HttpPost("GetReturnMessageRecord")]
- public Task>> GetReturnMessageRecord(GetReturnMessageRecordInput input)
- {
- return Task.FromResult(new UnifyResultDto>());
+ _warningRuleRepository = warningRuleRepository;
+ _warningDetailsEsRepository = warningDetailsEsRepository;
+ _returnWarningHandler = returnWarningHandler;
+ _trackStatusRepository = trackStatusRepository;
}
///
@@ -46,9 +37,163 @@ public class ReturnWarningService : ApplicationService
///
///
[HttpPost("GetReturnWarningRuleItem")]
- public Task>>
- GetReturnWarningRuleItem(GetReturnWarningRuleItemInput input)
+ public async Task>> GetReturnWarningRuleItem(GetReturnWarningRuleItemInput input)
{
- return Task.FromResult(new UnifyResultDto>());
+ var result = await _warningRuleRepository.GetReturnRuleItemsAsync(input.WarningId);
+
+ if (result.Count == 0)
+ return new UnifyResultDto>(true, new List());
+
+ // todo:缓存优化
+ var trackStatusIds = result
+ .SelectMany(x => x.TrackStatusIds.Split(',').Select(int.Parse))
+ .ToHashSet();
+ var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Status
+ })).ToDictionary(x => x.Id, y => y.Status);
+
+
+ var map = result.Select(x => new ReturnWarningRuleItemDto
+ {
+ Id = x.Id,
+ TrackStatus = BuildTrackStatus(x.TrackStatusIds),
+ ReturnTimeSpan = x.ReturnTimeSpan,
+ NotifyUsers = x.NotifyUsers.ToObject>()
+ });
+
+ return new UnifyResultDto>(true, map.ToList());
+
+ // todo:拆解优化
+ List BuildTrackStatus(string statusIds)
+ {
+ return statusIds.Split(',')
+ .Select(x =>
+ {
+ var id = int.Parse(x);
+ return new TrackStatusDto
+ {
+ TrackStatus = trackStatusDict.GetValueOrDefault(id),
+ TrackStatusId = id
+ };
+ }).ToList();
+ }
+ }
+
+ ///
+ /// 分页获取回传预警明细
+ ///
+ ///
+ ///
+ [HttpPost("GetPageReturnWarningDetails")]
+ public async Task> GetPageReturnWarningDetails(GetPageReturnWarningDetailsInput input)
+ {
+ var vo = ObjectMapper.Map(input);
+ var result = await _warningDetailsEsRepository.GetPageReturnWarningDetailsAsync(vo);
+
+ // :填充子系统名称(冗余?)
+ // :填充客户简称(冗余?)
+ // :填充订单类型名称(冗余?)
+ var map = result.List.Select(x => new ReturnWarningDetailsDto
+ {
+ EsId = x.Id,
+ SubSystemId = x.SubSystemId,
+ SubSystemName = x.SubSystemName,
+ OrderType = x.OrderType,
+ OrderTypeName = x.OrderTypeName,
+ OrderId = x.OrderId,
+ OrderNo = x.OrderNo,
+ Status = x.Status,
+ CustomId = x.CustomId,
+ CustomName = x.CustomName,
+ // 轨迹信息
+ TrackStatus = x.TrackStatus,
+ TrackCode = x.TrackCode,
+ TrackContent = x.TrackContent,
+ TrackPlace = x.TrackPlace,
+ TrackTime = x.TrackTime,
+ TrackTimeZone = x.TrackTimeZone,
+ TrackCreateTime = x.TrackCreateTime,
+ // 轨迹信息(映射后)
+ PushTrackCode = x.PushTrackCode,
+ PushTrackStatus = x.PushTrackStatus,
+ PushTrackContent = x.PushTrackContent,
+ // todo:计算属性
+ ActualReturnTimeSpan = x.ActualReturnTimeSpan,
+ SystemReturnTimeSpan = x.SystemReturnTimeSpan,
+ TrackCreateTimeSpan = x.TrackCreateTimeSpan,
+
+ // 具体描述
+ TrackReturnTime = x.TrackReturnTime,
+ ReturnTimeSpan = x.ReturnTimeSpan,
+ IsExistsKpi = x.IsExistsKpi,
+ RetryCount = x.RetryCount,
+ NotifyUserNames = ToUserNames(x.NotifyUsers),
+ CreateTime = x.CreateTime,
+ });
+
+ var sorted = map.OrderBy(x =>
+ {
+ // 人工介入置顶
+ if (x.Status == 1) return x.Status;
+ // 其他按创建时间从早到晚
+ return DateTimeHelper.ConvertToUnixTimestamp(x.CreateTime);
+ });
+
+ return new UnifyPageResultDto(
+ sorted.ToList(),
+ result.Pagination.PageIndex,
+ result.Pagination.PageSize,
+ result.Pagination.Total);
+
+ // 通知用户提取用户名称
+ string ToUserNames(string notifyUsers)
+ {
+ if (string.IsNullOrWhiteSpace(notifyUsers))
+ return string.Empty;
+ return string.Join(',', notifyUsers.ToObject>().Select(x => x.UserName));
+ }
+ }
+
+ ///
+ /// 获取回传报文日志
+ ///
+ [HttpPost("GetReturnMessageRecord")]
+ public async Task>> GetReturnMessageRecord(GetReturnMessageRecordInput input)
+ {
+ var result = await _warningDetailsEsRepository.GetReturnMessageRecordListByIdAsync(input.WarningDetailsId);
+
+ var map = result.Select(x => new ReturnMessageRecordDto
+ {
+ EsId = x.Id,
+ ReturnWarningDetailsId = x.WarningDetailsId,
+ IsSuccess = x.IsSuccess,
+ Message = x.Message,
+ CreateTime = x.CreateTime
+ });
+
+ return new UnifyResultDto>(true, map.ToList());
+ }
+
+
+ ///
+ /// 编辑回传预警规则列表
+ ///
+ ///
+ ///
+ [HttpPost("EditReturnWarningRuleItem")]
+ public async Task EditReturnWarningRuleItem(EditReturnWarningRuleItemInput input)
+ {
+ var rule = await _warningRuleRepository.GetWarningRuleByIdAsync(input.WarningId, WarningRuleType.回传时效预警);
+ if (rule == null)
+ {
+ throw new BusinessException(message: $"预警规则主体不存在,WarningId=[{input.WarningId}]");
+ }
+
+ var bos = ReturnWarningRuleItemBO.From(input);
+ await _returnWarningHandler.HandleEditAsync(rule, bos);
+
+ return new UnifyResultDto(true);
}
}
diff --git a/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs b/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs
index c9881318..c5899c38 100644
--- a/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/TransportWarningService.cs
@@ -1,4 +1,18 @@
+using System.Text;
+using SJZY.Expand.ABP.Core.PublicMethords;
+using SJZY.Track.Application.Contract.Dtos.Warning;
using SJZY.Track.Application.Contract.Dtos.Warning.Transport;
+using SJZY.Track.Application.Helpers;
+using SJZY.Track.Application.Services.Warning.Handlers.Model;
+using SJZY.Track.Application.Services.Warning.Handlers.Warning;
+using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
+using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+using SJZY.Track.Domain.Dtos.Warning;
+using SJZY.Track.Domain.Enums;
+
+namespace SJZY.Track.Application.Services.Warning;
///
/// 运输时效预警服务
@@ -7,65 +21,259 @@ using SJZY.Track.Application.Contract.Dtos.Warning.Transport;
[Route("Warning/Transport")]
public class TransportWarningService : ApplicationService
{
+ private readonly IWarningRuleRepository _warningRuleRepository;
+ private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
+ private readonly ITransportWarningHandler _transportWarningHandler;
+ private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
+ private readonly ITrackStatusRepository _trackStatusRepository;
- ///
- /// 编辑预警规则项目(全量)
- ///
- ///
- ///
- [HttpPost("EditTransportWarningSceneRuleItem")]
- public Task
- EditTransportWarningSceneRuleItem(EditTransportWarningSceneRuleItemInput input)
- {
- return Task.FromResult(new UnifyResultDto());
- }
+ public TransportWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, ITransportWarningHandler transportWarningHandler, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackStatusRepository trackStatusRepository)
+ {
+ _warningRuleRepository = warningRuleRepository;
+ _warningDetailsEsRepository = warningDetailsEsRepository;
+ _transportWarningHandler = transportWarningHandler;
+ _trackDetailsEsRepository = trackDetailsEsRepository;
+ _trackStatusRepository = trackStatusRepository;
+ }
+ ///
+ /// 获取预警规则场景
+ ///
+ ///
+ ///
+ [HttpPost("GetTransportWarningScene")]
+ public async Task>> GetTransportWarningScene(GetTransportWarningSceneInput input)
+ {
+ var entities = await _warningRuleRepository.GetTransportSceneAsync(input.WarningId);
- ///
- /// 分页获取运输时效预警明细
- ///
- ///
- ///
- [HttpPost("GetPageTransportWarningDetails")]
- public Task>
- GetPageTransportWarningDetails(GetPageTransportWarningDetailsInput input)
- {
- return Task.FromResult(new UnifyPageResultDto());
- }
+ var map = entities.Select(x => new TransportWarningSceneDto
+ {
+ Id = x.Id,
+ WarningId = x.WarningId,
+ Summary = BuildSummary(x),
+ IsTransit = x.IsTransit,
+ CargoType = x.CargoType,
+ LeavePort = x.LeavePort,
+ ProductCode = x.ProductCode,
+ Months = x.Months,
+ AreaId = x.AreaId
+ });
- ///
- /// 获取预警规则场景
- ///
- ///
- ///
- [HttpPost("GetTransportWarningScene")]
- public Task>>
- GetTransportWarningScene(GetTransportWarningSceneInput input)
- {
- return Task.FromResult(new UnifyResultDto>());
- }
+ return new UnifyResultDto>(true, map.ToList());
- ///
- /// 获取运输时效场景规则项目
- ///
- ///
- ///
- [HttpPost("GetTransportWarningSceneRuleItem")]
- public Task>>
- GetTransportWarningSceneRuleItem(GetTransportWarningSceneRuleItemInput input)
- {
- return Task.FromResult(new UnifyResultDto>());
- }
+ // 构建场景摘要
+ string BuildSummary(TransportWarningSceneEntity entity)
+ {
+ var sb = new StringBuilder();
+ // 货物类型
+ if (!string.IsNullOrWhiteSpace(entity.CargoType))
+ sb.Append($"{entity.CargoType}");
+ // 月份
+ if (!string.IsNullOrWhiteSpace(entity.Months))
+ sb.Append($"/{entity.Months.Replace("/", string.Empty)}月份");
+ // 中转
+ if (entity.IsTransit != null)
+ sb.Append($"/中转为{(entity.IsTransit.Value ? "是" : "否")}");
+ // 起运港口
+ if (!string.IsNullOrWhiteSpace(entity.LeavePort))
+ sb.Append($"/{entity.LeavePort}");
+ // 产品编码
+ if (!string.IsNullOrWhiteSpace(entity.ProductCode))
+ sb.Append($"/{entity.ProductCode}");
- ///
- /// 新增/更新 运输时效场景
- ///
- ///
- ///
- [HttpPost("UpsertTransportWarningScene")]
- public Task>
- UpsertTransportWarningScene(UpsertTransportWarningSceneInput input)
- {
- return Task.FromResult(new UnifyResultDto());
- }
+ return sb.ToString();
+ }
+ }
+
+ ///
+ /// 获取运输时效场景规则项目
+ ///
+ ///
+ ///
+ [HttpPost("GetTransportWarningSceneRuleItem")]
+ public async Task>> GetTransportWarningSceneRuleItem(GetTransportWarningSceneRuleItemInput input)
+ {
+ var entities = await _warningRuleRepository.GetTransportSceneRuleItemsAsync(input.WarningId, input.SceneId);
+
+ // todo:缓存优化
+ var trackStatusIds = entities.SelectMany(x => new List(2)
+ {
+ x.StartTrackStatusId,
+ x.EndTrackStatusId
+ }).ToHashSet();
+ var trackStatusDict = (await _trackStatusRepository.GetListAsync(x => trackStatusIds.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Status
+ })).ToDictionary(x => x.Id, y => y.Status);
+
+ var map = entities.Select(x => new TransportWarningSceneRuleItemDto
+ {
+ Id = x.Id,
+ StartTrackStatusId = x.StartTrackStatusId,
+ StartTrackStatus = trackStatusDict.GetValueOrDefault(x.StartTrackStatusId),
+ EndTrackStatusId = x.EndTrackStatusId,
+ EndTrackStatus = trackStatusDict.GetValueOrDefault(x.EndTrackStatusId),
+ TransportTimeSpan = x.TransportTimeSpan,
+ StartTrackWarningTimeSpan = x.StartTrackWarningTimeSpan,
+ NotifyUsers = x.NotifyUsers.ToObject>()
+ });
+
+ return new UnifyResultDto>(true, map.ToList());
+ }
+
+ ///
+ /// 分页获取运输时效预警明细
+ ///
+ ///
+ ///
+ [HttpPost("GetPageTransportWarningDetails")]
+ public async Task> GetPageTransportWarningDetails(GetPageTransportWarningDetailsInput input)
+ {
+ var vo = ObjectMapper.Map(input);
+ var result = await _warningDetailsEsRepository.GetPageTransportWarningDetailsAsync(vo);
+ if (result.List.Count == 0)
+ {
+ return new UnifyPageResultDto(new List(), input.PageIndex, input.PageSize, 0);
+ }
+
+ var orderIds = result.List.Select(x => x.OrderId).ToHashSet();
+ var orderTracks = await _trackDetailsEsRepository.GetLatestListAsync(orderIds);
+ var orderIdTrackDict = orderTracks.ToDictionary(x => x.OrderId);
+
+ // :填充子系统名称(冗余?)
+ // :填充客户简称(冗余?)
+ // :填充订单类型名称(冗余?)
+ var map = result.List.Select(x =>
+ {
+ var orderIdTrack = orderIdTrackDict.GetValueOrDefault(x.OrderId);
+ return new TransportWarningDetailsDto
+ {
+ EsId = x.Id,
+ SubSystemId = x.SubSystemId,
+ SubSystemName = x.SubSystemName,
+ CustomId = x.CustomId,
+ CustomName = x.CustomName,
+ OrderId = x.OrderId,
+ OrderNo = x.OrderNo,
+ OrderType = x.OrderType,
+ OrderTypeName = x.OrderTypeName,
+ NotifyUserNames = ToUserNames(x.NotifyUsers),
+
+ // 最新轨迹 (不冗余)
+ LatestTrackContent = orderIdTrack?.TrackContent,
+ LatestTrackTime = orderIdTrack?.TrackTime,
+ LatestTrackTimeZone = orderIdTrack?.TrackTimeZone,
+ LatestTrackPlace = orderIdTrack?.TrackContent,
+
+ // 起始轨迹
+ StartTrackStatus = x.StartTrackStatus,
+ StartTrackContent = x.StartTrackContent,
+ StartTrackTime = x.StartTrackTime,
+ StartTrackTimeZone = x.StartTrackTimeZone,
+
+ // 截止轨迹
+ EndTrackStatus = x.EndTrackStatus,
+ EndTrackContent = x.EndTrackContent,
+ EndTrackTime = x.EndTrackTime,
+ EndTrackTimeZone = x.EndTrackTimeZone,
+
+ WarningName = x.WarningName,
+ WarningRuleDescription = x.WarningRuleDescription,
+
+ // 累计运输时间
+ CumulativeTimeSpan = FormatCumulativeTimeSpan(x.CumulativeTimeSpan),
+
+ Status = x.Status,
+ CreateTime = x.CreateTime
+ };
+ });
+
+ var sorted = map.OrderBy(x =>
+ {
+ // 即将超时,已超时置顶
+ if (x.Status is 1 or 2) return x.Status;
+ // 其他按创建时间从早到晚
+ return DateTimeHelper.ConvertToUnixTimestamp(x.CreateTime);
+ });
+
+ return new UnifyPageResultDto(
+ sorted.ToList(),
+ result.Pagination.PageIndex,
+ result.Pagination.PageSize,
+ result.Pagination.Total);
+
+ // 通知用户提取用户名称
+ string ToUserNames(string notifyUsers)
+ {
+ if (string.IsNullOrWhiteSpace(notifyUsers))
+ return string.Empty;
+ return string.Join(',', notifyUsers.ToObject>().Select(x => x.UserName));
+ }
+
+ // 格式化累计运输时间为文本形式
+ string FormatCumulativeTimeSpan(long cumulativeTimeSpan)
+ {
+ var timeSpan = TimeSpan.FromMilliseconds(cumulativeTimeSpan);
+
+ return $"{timeSpan.Days:00}天{timeSpan.Hours:00}小时{timeSpan.Minutes:00}分钟";
+ }
+ }
+
+ ///
+ /// 新增/更新 运输时效场景
+ ///
+ ///
+ ///
+ [HttpPost("UpsertTransportWarningScene")]
+ public async Task> UpsertTransportWarningScene(UpsertTransportWarningSceneInput input)
+ {
+ var rule = await _warningRuleRepository.GetWarningRuleByIdAsync(input.WarningId, WarningRuleType.运输时效预警);
+ if (rule == null)
+ {
+ throw new BusinessException(message: $"预警规则主体不存在,WarningId=[{input.WarningId}]");
+ }
+
+ var postBo = TransportWarningSceneBO.From(input);
+ // 查出旧场景
+ var oldScene = await _warningRuleRepository.GetTransportSceneAsync(input.WarningId, input.Id);
+ var oldBo = oldScene != null ? TransportWarningSceneBO.From(oldScene) : null;
+
+ // 更新或者新增
+ var id = await _warningRuleRepository.UpsertTransportSceneReturnIdAsync(postBo.ToEntity());
+
+ if (oldBo != null)
+ await _transportWarningHandler.HandleSceneChangedAsync(rule, oldBo, postBo);
+
+ return new UnifyResultDto(true, new IdBaseDto
+ {
+ Id = id
+ });
+ }
+
+ ///
+ /// 编辑预警规则项目(全量)
+ ///
+ ///
+ ///
+ [HttpPost("EditTransportWarningSceneRuleItem")]
+ public async Task EditTransportWarningSceneRuleItem(EditTransportWarningSceneRuleItemInput input)
+ {
+ var rule = await _warningRuleRepository.GetWarningRuleByIdAsync(input.WarningId, WarningRuleType.运输时效预警);
+ if (rule == null)
+ {
+ throw new BusinessException(message: $"预警规则主体不存在,WarningId=[{input.WarningId}]");
+ }
+
+ var ruleScene = await _warningRuleRepository.GetTransportSceneAsync(input.WarningId, input.SceneId);
+ if (ruleScene == null)
+ {
+ throw new BusinessException(message: $"运输时效规则场景不存在,WarningIdId=[{input.WarningId}] SceneId=[{input.SceneId}]");
+ }
+
+ var postRuleItems = TransportWarningSceneRuleItemBO.From(input);
+ await _transportWarningHandler.HandleEditAsync(rule, ruleScene, postRuleItems);
+
+ return new UnifyResultDto(true);
+ }
}
diff --git a/src/SJZY.Track.Application/Services/Warning/WarningService.cs b/src/SJZY.Track.Application/Services/Warning/WarningService.cs
index a0be7481..19d8f8a1 100644
--- a/src/SJZY.Track.Application/Services/Warning/WarningService.cs
+++ b/src/SJZY.Track.Application/Services/Warning/WarningService.cs
@@ -1,4 +1,6 @@
using SJZY.Track.Application.Contract.Dtos.Warning;
+using SJZY.Track.Domain.Aggregates.WarningAggregate;
+using SJZY.Track.Domain.Queries;
namespace SJZY.Track.Application.Services.Warning;
@@ -9,6 +11,17 @@ namespace SJZY.Track.Application.Services.Warning;
[Route("Warning")]
public class WarningService : ApplicationService
{
+ private readonly IWarningRuleRepository _warningRuleRepository;
+ private readonly IVSystemQueries _vSystemQueries;
+ private readonly IVExternalSubjectQueries _vExternalSubjectQueries;
+
+ public WarningService(IWarningRuleRepository warningRuleRepository, IVSystemQueries vSystemQueries, IVExternalSubjectQueries vExternalSubjectQueries)
+ {
+ _warningRuleRepository = warningRuleRepository;
+ _vSystemQueries = vSystemQueries;
+ _vExternalSubjectQueries = vExternalSubjectQueries;
+ }
+
///
/// 新增/修改预警规则主体
///
@@ -17,18 +30,24 @@ public class WarningService : ApplicationService
[HttpPost("UpsertWarningRule")]
public async Task> UpsertWarningRule(UpsertWarningRuleInput input)
{
- // var id = await _warningRuleRepository.UpsertReturnIdAsync(new WarningRuleEntity(
- // input.Id,
- // input.Name,
- // input.SubSystemId,
- // input.CustomId,
- // input.IsEnabled,
- // input.WarningType)
- // );
+ // 要求 SubSystemId+CustomId+Name 联合不能重复
+ if (await _warningRuleRepository.CheckNameDuplicateAsync(input.Id, input.SubSystemId, input.CustomId, input.Name))
+ {
+ throw new BusinessException(message: $"SubSystemId:[{input.SubSystemId}],CustomId:[{input.CustomId}],已存在名称为[{input.Name}]规则,不允许重复添加/修改");
+ }
+
+ var id = await _warningRuleRepository.UpsertReturnIdAsync(new WarningRuleEntity(
+ input.Id,
+ input.Name,
+ input.SubSystemId,
+ input.CustomId,
+ input.IsEnabled,
+ input.WarningType)
+ );
return new UnifyResultDto(true, new IdBaseDto
{
- Id = input.Id
+ Id = id
});
}
@@ -38,9 +57,40 @@ public class WarningService : ApplicationService
///
///
[HttpPost("GetWarningRule")]
- public Task>> GetWarningRule(GetWarningRuleInput input)
+ public async Task>> GetWarningRule(GetWarningRuleInput input)
{
- //var result = await _warningRuleRepository.GetWarningRuleListAsync(input.SubSystemId, input.KeyWord, input.IsEnabled, input.WarningType);
- throw new NotImplementedException();
+ var result = await _warningRuleRepository.GetWarningRuleListAsync(input.SubSystemId, input.KeyWord, input.IsEnabled, input.WarningType);
+ if (result.Count == 0)
+ return new UnifyResultDto>(true, new List());
+
+ // todo:缓存优化
+ var customIds = result.Select(x => x.CustomId).ToHashSet();
+ var customDict = (await _vExternalSubjectQueries
+ .GetListAsync(x => customIds.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.Abbreviation
+ })).ToDictionary(x => x.Id, x => x.Abbreviation);
+
+ var subSystemIds = result.Select(x => x.SubSystemId).ToHashSet();
+ var subSystemDict = (await _vSystemQueries
+ .GetListAsync(x => subSystemIds.Contains(x.Id), x => new
+ {
+ x.Id,
+ x.CnName
+ })).ToDictionary(x => x.Id, x => x.CnName);
+
+ return new UnifyResultDto>(true, result.Select(x => new WarningRuleDto
+ {
+ Id = x.Id,
+ SubSystemId = x.SubSystemId,
+ SubSystemName = customDict.GetValueOrDefault(x.SubSystemId),
+ CustomId = x.CustomId,
+ CustomName = subSystemDict.GetValueOrDefault(x.CustomId),
+ Name = x.Name,
+ IsEnabled = x.IsEnabled,
+ WarningType = x.WarningType,
+ Version = x.Version
+ }).ToList());
}
}
diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs
index 7548d8d8..718124c6 100644
--- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs
+++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs
@@ -10,7 +10,7 @@ public interface IOrderRepository : IBasicRepository
/// key:OrderType value:TypeName
///
///
- Task> GetTrackOrderTypeDict();
+ Task> GetTrackOrderTypeDictAsync();
///
/// 获取分页的轨迹订单
diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs
index ecd623be..916f6ded 100644
--- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs
+++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs
@@ -8,8 +8,7 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService> GetListAsync(int[] orderIds, string trackCode, bool forUpsert = false);
- // todo:s07 获取这些订单的最新一条轨迹
- // Task> GetLatestListAsync(HashSet eventOrderIds);
+ Task> GetLatestListAsync(HashSet eventOrderIds);
Task> GetLatestListAsync(int[] eventOrderIds, List trackCodes);
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs
new file mode 100644
index 00000000..eb124570
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningDetailsIndex.cs
@@ -0,0 +1,45 @@
+using Nest;
+using SJZY.Expand.ElasticSearch;
+using SJZY.Track.Domain.Consts;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
+
+[ElasticsearchType(RelationName = GlobalConst.CompleteWarningDetailsIndex)]
+public sealed class CompleteWarningDetailsIndex : IdBaseIndex
+{
+ public string IndexName { get; set; }
+ public int WarningId { get; set; }
+ public int CompleteWarningRuleId { get; set; }
+ public string Version { get; set; }
+
+ //public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+ public int CheckPointTrackStatusId { get; set; } // (冗余)检查点轨迹状态Id
+ public string MissingTrackStatusIds { get; set; } //(冗余)缺失的轨迹状态
+
+ //订单信息
+ public int SubSystemId { get; set; } //(冗余)子系统Id
+ public string SubSystemName { get; set; } //(冗余)子系统名称
+ public int CustomId { get; set; } //(冗余)客户Id
+ public string CustomName { get; set; } //(冗余)客户名称
+ public int OrderId { get; set; }
+ public string OrderNo { get; set; } //订单号
+ public int OrderType { get; set; } //(冗余)订单类型
+ public string OrderTypeName { get; set; } //(冗余)订单类型名称
+
+ //可变属性
+ public int Status { get; set; } // 1:待处理,2:已处理,3:已关闭
+
+ //视图属性(todo:查es 最新)
+ // public int LatestTrackStatusId { get; set; } //最新轨迹状态Id
+ // public string LatestTrackStatus { get; set; } //(冗余)最新轨迹状态
+ // public int LatestTrackContentId { get; set; } //最新轨迹内容Id
+ // public string LatestTrackContent { get; set; } //(冗余)最新轨迹内容名称
+ // public DateTime LatestTrackTime { get; set; } //最新轨迹发生时间
+ // public float LatestTrackTimeZone { get; set; } //最新轨迹发生时区
+ // public string LatestTrackPlace { get; set; } //最新轨迹发生地
+
+ //审计属性
+ public DateTime CreateTime { get; set; } // 预警创建时间
+ public DateTime? ProcessedTime { get; set; } // 预警处理时间
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs
new file mode 100644
index 00000000..04921828
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Complete/CompleteWarningRuleItemEntity.cs
@@ -0,0 +1,84 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
+
+[SugarTable("t_warning_complete_rule_item", TableDescription = "完整预警规则项")]
+public sealed class CompleteWarningRuleItemEntity : IFullAuditedBasicEntitys, IEntity
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "WarningId", ColumnDescription = "预警规则主体id")]
+ public int WarningId { get; set; }
+
+ [SugarColumn(ColumnName = "OrderTypes", ColumnDescription = "订单类型集合(,分割)")]
+ public string OrderTypes { get; set; } //订单类型, 逗号分隔(1,3)
+
+ [SugarColumn(ColumnName = "CheckPointTrackStatusId", ColumnDescription = "检查点轨迹状态id")]
+ public int CheckPointTrackStatusId { get; set; } //检查点轨迹状态id
+
+ [SugarColumn(ColumnName = "RequireTrackStatusIdExpression", ColumnDescription = "要求该订单持有的轨迹状态的表达式 S1/S2,S3 代表: 存在状态S1或者S2并且存在S3才算")]
+ public string RequireTrackStatusIdExpression { get; set; } //要求该订单持有的轨迹状态的表达式 S1/S2,S3 代表: 存在状态S1或者S2并且存在S3
+
+ // [SugarColumn(ColumnName = "NotifyModes", ColumnDescription = "通知方式,多个方式(,)分割 eg: 1,2")]
+ // public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+
+ [SugarColumn(ColumnName = "NotifyUsers", ColumnDescription = "通知人Json eg: [{\"UserId\":1,\"UserName\":\"张三\"},{\"UserId\":2,\"UserName\":\"李四\"}]")]
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+
+ public CompleteWarningRuleItemEntity()
+ {
+ }
+
+
+ public CompleteWarningRuleItemEntity(int id, int warningId, string orderTypes, int checkPointTrackStatusId, string requireTrackStatusIdExpression, string notifyUsers)
+ {
+ Id = id;
+ WarningId = warningId;
+ OrderTypes = orderTypes;
+ CheckPointTrackStatusId = checkPointTrackStatusId;
+ RequireTrackStatusIdExpression = requireTrackStatusIdExpression;
+ NotifyUsers = notifyUsers;
+ }
+
+ public HashSet GetRuleOrderTypes()
+ {
+ return OrderTypes.Split(',').Select(int.Parse).ToHashSet();
+ }
+
+ public List> GetRequireTrackStatusIdGroups()
+ {
+ return RequireTrackStatusIdExpression
+ .Split(",")
+ .Select(g => g.Split('/').Select(int.Parse).ToHashSet())
+ .ToList();
+ }
+
+ // 查看是否能命中这个规则
+ public bool CanHitRule(int orderType, int trackStatusId)
+ {
+ var orderTypes = GetRuleOrderTypes();
+ //没有命中订单类型
+ if (!orderTypes.Contains(orderType)) return false;
+ //没有命中状态检查点
+ if (trackStatusId != CheckPointTrackStatusId) return false;
+
+ return true;
+ }
+
+ // 根据轨迹状态id集合判断是否缺失轨迹状态
+ public bool ExistsMissingTrackStatus(HashSet trackStatusIds)
+ {
+ if (trackStatusIds.Count == 0) return true;
+
+ //组之间是并且关系,组内为或的关系
+ var groups = GetRequireTrackStatusIdGroups();
+
+ // 当没有某个组没有交集产生,则认定为轨迹缺失
+ foreach (var g in groups)
+ {
+ if (!g.Intersect(trackStatusIds).Any())
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningDetailsEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningDetailsEsRepository.cs
new file mode 100644
index 00000000..335e2337
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningDetailsEsRepository.cs
@@ -0,0 +1,85 @@
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+using SJZY.Track.Domain.Dtos.Warning;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate;
+
+public interface IWarningDetailsEsRepository
+{
+ #region 运输预警明细
+
+ // 分页获取运输预警明细
+ Task> GetPageTransportWarningDetailsAsync(GetPageTransportWarningDetailsInputVO input);
+
+ // 获取运输预警明细(预警规则id+状态)
+ Task> GetTransportWarningDetailsAsync(HashSet ruleItemIds, HashSet status);
+
+ // 更新运输预警明细
+ Task UpdateTransportWarningDetailsAsync(TransportWarningDetailsIndex detail);
+
+ // 批量更新运输预警明细
+ Task BulkUpdateTransportWarningDetailsAsync(List details, int maxRetries = 3);
+
+ // 批量关闭运输预警明细
+ Task BulkCloseTransportWarningDetailsAsync(HashSet detailIds, int maxRetries = 3);
+ // 批量关闭运输预警明细
+ Task BulkCloseTransportWarningDetailsAsync(HashSet ruleItemIds, int maxRetries = 3);
+
+ // 新增运输预警明细
+ Task InsertTransportWarningDetailsAsync(TransportWarningDetailsIndex detail);
+
+ // 批量新增运输预警明细
+ Task BulkInsertTransportWarningDetailsAsync(List details, int maxRetries = 3);
+
+ #endregion
+
+ #region 回传预警明细
+
+ // 分页获取回传预警明细
+ Task> GetPageReturnWarningDetailsAsync(GetPageReturnWarningDetailsInputVO input);
+
+ // 获取回传日志列表
+ Task> GetReturnMessageRecordListByIdAsync(string esId);
+
+ // 更新回传预警明细
+ Task UpdateReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail);
+
+ // 批量更新回传预警明细
+ Task BulkUpdateReturnWarningDetailsAsync(List details, int maxRetries = 3);
+
+ // 新增回传预警明细
+ Task InsertReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail);
+
+ // 批量新增回传预警明细
+ Task BulkInsertReturnWarningDetailsAsync(List details, int maxRetries = 3);
+
+ // 新增回传日志
+ Task InsertReturnMessageRecordAsync(ReturnMessageRecordIndex detail);
+
+ // 批量新增回传日志
+ Task BulkInsertReturnMessageRecordAsync(List details, int maxRetries = 3);
+
+ #endregion
+
+ #region 完整预警明细
+
+ // 分页获取完整预警明细
+ Task> GetPageCompleteWarningDetailsAsync(GetPageCompleteWarningDetailsInputVO input);
+
+ // 更新完整预警明细
+ Task UpdateCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail);
+
+ // 批量完整回传预警明细
+ Task BulkUpdateCompleteWarningDetailsAsync(List details, int maxRetries = 3);
+
+ // 新增完整预警明细
+ Task InsertCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail);
+
+ // 批量新增完整预警明细
+ Task BulkInsertCompleteWarningDetailsAsync(List details, int maxRetries = 3);
+
+ #endregion
+
+ Task CreateAliasAsync();
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningRuleRepository.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningRuleRepository.cs
new file mode 100644
index 00000000..59415873
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningRuleRepository.cs
@@ -0,0 +1,92 @@
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Complete;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+using SJZY.Track.Domain.Enums;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate;
+
+///
+/// 预警规则仓储
+/// todo:需要使用vo
+///
+public interface IWarningRuleRepository : IBasicRepository
+{
+ #region 规则主体
+
+ // 检查名称是否重复
+ Task CheckNameDuplicateAsync(int id,int subsystemId, int customId, string name);
+
+ // 新增/更新预警规则主体,并返回id
+ Task UpsertReturnIdAsync(WarningRuleEntity entity);
+
+ // 更新版本号
+ Task UpdateVersionAsync(WarningRuleEntity entity);
+
+ // 模糊查询预警规则主体
+ Task> GetWarningRuleListAsync(int? subsystemId, string? keyword, bool? isEnabled, int? warningType);
+
+ // 获取启用的预警规则主体
+ Task GetWarningRuleForEnabledAsync(int subSystemId, int customId, WarningRuleType warningType);
+
+ // 获取预警规则主体根据id
+ Task GetWarningRuleByIdAsync(int id, WarningRuleType? warningType = null);
+
+ #endregion
+
+ #region 运输时效预警规则
+
+ // 获取运输预警场景列表
+ Task> GetTransportSceneAsync(int warningId);
+
+ // 获取运输预警场景列表
+ Task GetTransportSceneAsync(int warningId, int sceneId);
+
+ // 全量获取的运输时效场景规则项目
+ Task> GetTransportSceneRuleItemsAsync(int warningId, int sceneId);
+
+ // 新增/更新 运输预警场景
+ Task UpsertTransportSceneReturnIdAsync(TransportWarningSceneEntity entity);
+
+ // 批量更新运输时效场景规则项目
+ Task BulkUpdateTransportSceneRuleItemsAsync(List entities);
+
+ // 批量新增运输时效场景规则项目
+ Task BulkInsertTransportSceneRuleItemsAsync(List entities);
+
+ // 删除运输预警场景规则项目
+ Task DeleteTransportSceneRuleItemsAsync(HashSet ruleItemIds);
+
+ #endregion
+
+ #region 回传时效预警规则
+
+ // 获取全量回传预警规则规则项目
+ Task> GetReturnRuleItemsAsync(int warningId);
+
+ // 批量新增回传时效场景规则项目
+ Task BulkInsertReturnRuleItemsAsync(List entities);
+
+ // 批量更新回传预警规则规则项目
+ Task BulkUpdateReturnRuleItemsAsync(List entities);
+
+ // 删除回传预警规则项目
+ Task DeleteReturnRuleItemsAsync(HashSet ruleItemIds);
+
+ #endregion
+
+ #region 完整预警规则
+
+ // 获取全量预警规则规则项目
+ Task> GetCompleteRuleItemsAsync(int warningId);
+
+ // 批量更新预警规则规则项目
+ Task BulkUpdateCompleteRuleItemsAsync(List entities);
+
+ // 批量新增完整时效规则项目
+ Task BulkInsertCompleteRuleItemsAsync(List entities);
+
+ // 删除完整预警场景规则项目
+ Task DeleteCompleteRuleItemsAsync(HashSet ruleItemIds);
+
+ #endregion
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningTaskRepository.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningTaskRepository.cs
new file mode 100644
index 00000000..367e8998
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/IWarningTaskRepository.cs
@@ -0,0 +1,76 @@
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate;
+
+public interface IWarningTaskRepository
+{
+ #region 预警通知任务
+
+ // 初步扫描出可能要进行的预警通知任务
+ Task> ScanMayNeedExecutedTaskAsync();
+
+ // 获取预警通知任务
+ Task> GetWarningNotifyTaskAsync(Expression> expression);
+
+ // 添加一个预警通知任务
+ Task AddWarningNotifyTaskAsync(WarningNotifyTaskEntity entity);
+
+ // 批量添加预警通知任务
+ Task BulkInsertWarningNotifyTaskAsync(List entities);
+
+ // 关闭预警通知任务
+ Task CloseWarningNotifyTaskAsync(Expression> expression);
+
+ // 关闭预警通知任务
+ Task CloseWarningNotifyTaskAsync(WarningNotifyTaskEntity entity);
+
+ #endregion
+
+ #region 回传预警_重试推送任务
+
+ // 扫描重试推送任务
+ Task> ScanReturnWarningRetryPushTaskAsync();
+
+ // 条件获取重试推送任务
+ Task> GetReturnWarningRetryPushTaskAsync(Expression> expression);
+
+ // 添加回传预警_重试推送任务
+ Task AddReturnWarningRetryPushTaskAsync(ReturnWarningRetryPushTaskEntity entity);
+
+ // 批量添加回传预警_重试推送任务
+ Task BulkInsertReturnWarningRetryPushTaskAsync(List entities);
+
+ // 条件关闭回传预警_重试推送任务
+ Task CloseReturnWarningRetryPushTaskAsync(Expression> expression);
+
+ // 关闭回传预警_重试推送任务
+ Task CloseReturnWarningRetryPushTaskAsync(ReturnWarningRetryPushTaskEntity entity);
+
+ #endregion
+
+ #region 运输预警_预警明细生成任务
+
+ // 扫描预警明细生成任务
+ Task> ScanTransportWarningDetailsGenerateTaskAsync();
+
+ // 条件获取运输预警明细生成任务
+ Task> GetTransportWarningDetailsGenerateTaskAsync(Expression> expression);
+
+ // 添加运输预警明细生成任务
+ Task AddTransportWarningDetailsGenerateTaskAsync(TransportWarningDetailsGenerateTaskEntity entity);
+
+ // 批量添加运输预警明细生成任务
+ Task BulkInsertTransportWarningDetailsGenerateTaskAsync(List entities);
+
+ // 批量更新运输预警明细生成任务
+ Task BulkUpdateTransportWarningDetailsGenerateTaskAsync(List entities);
+
+ // 条件关闭运输预警明细生成任务
+ Task CloseTransportWarningDetailsGenerateTaskAsync(Expression> expression);
+
+ // 关闭运输预警明细生成任务
+ Task CloseTransportWarningDetailsGenerateTaskAsync(TransportWarningDetailsGenerateTaskEntity entity);
+
+ #endregion
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnMessageRecordIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnMessageRecordIndex.cs
new file mode 100644
index 00000000..1915550c
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnMessageRecordIndex.cs
@@ -0,0 +1,17 @@
+using Nest;
+using SJZY.Expand.ElasticSearch;
+using SJZY.Track.Domain.Consts;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+
+[ElasticsearchType(RelationName = GlobalConst.ReturnMessageRecordIndex)]
+public class ReturnMessageRecordIndex : IdBaseIndex
+{
+ public string IndexName { get; set; }
+ public string WarningDetailsId { get; set; } //回传预警明细Id
+ public bool IsSuccess { get; set; } //是否成功
+ public string Message { get; set; } //报文内容 Json字符串
+
+ //审计属性
+ public DateTime CreateTime { get; set; } //报文创建时间
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs
new file mode 100644
index 00000000..a064b689
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningDetailsIndex.cs
@@ -0,0 +1,82 @@
+using Nest;
+using SJZY.Expand.ElasticSearch;
+using SJZY.Track.Domain.Consts;
+using SJZY.Track.Domain.Extensions;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+
+// 回传时效预警明细
+[ElasticsearchType(RelationName = GlobalConst.ReturnWarningDetailsIndex)]
+public class ReturnWarningDetailsIndex : IdBaseIndex
+{
+ public string IndexName { get; set; }
+ //是否存在KPI考核,根据是否命中规则
+ public bool IsExistsKpi => ReturnWarningRuleId != null && ReturnWarningRuleId > 0;
+ public int? WarningId { get; set; }
+ public int? ReturnWarningRuleId { get; set; }
+ public string? Version { get; set; } //预警规则版本
+ public float? ReturnTimeSpan { get; set; } //(冗余)回传时效(单位小时)
+ //public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+
+ //订单信息
+ public int SubSystemId { get; set; } //(冗余)子系统Id
+ public string SubSystemName { get; set; } //(冗余)子系统名称
+ public int CustomId { get; set; } //(冗余)客户Id
+ public string CustomName { get; set; } //(冗余)客户名称
+ public int OrderId { get; set; }
+ public string OrderNo { get; set; } //订单号
+ public int OrderType { get; set; } //(冗余)订单类型
+ public string OrderTypeName { get; set; } //(冗余)订单类型名称
+
+ //轨迹信息-原始
+ public int TrackStatusId { get; set; }
+ public string TrackStatus { get; set; } //(冗余)轨迹状态名称
+ public string? CompareFields { get; set; } //(冗余)比较字段
+ public string? Extra { get; set; } //扩展字段
+ public int TrackContentId { get; set; }
+ public string TrackContent { get; set; }
+ public string TrackCode { get; set; }
+ public string TrackPlace { get; set; } //轨迹发生地
+ public DateTime TrackTime { get; set; } //轨迹发生时间
+ public float TrackTimeZone { get; set; } //轨迹发生时区
+ public DateTime TrackCreateTime { get; set; } //轨迹创建时间
+
+ //轨迹信息-映射后
+ public string PushTrackStatus { get; set; } //(冗余)推送轨迹状态
+ public string PushTrackCode { get; set; }
+ public string PushTrackContent { get; set; }
+ public string PushTrackEnContent { get; set; }
+
+ //可变属性
+ public DateTime? TrackReturnTime { get; set; } //轨迹回传时间, tips:只有回传成功了才写入
+ public int RetryCount { get; set; } // 回传重试次数
+ public int Status { get; set; } // 1:人工介入 2:重试中 3:推送完成 4:已关闭
+
+ //计算属性
+ public long? ActualReturnTimeSpan { get; set; } //实际回传用时(单位毫秒)
+ public long? SystemReturnTimeSpan { get; set; } //系统回传用时 (单位毫秒)
+ public long TrackCreateTimeSpan { get; set; } //轨迹创建用时(单位毫秒)
+
+ //审计属性
+ public DateTime CreateTime { get; set; } // 预警创建时间
+ public DateTime? UpdateTime { get; set; } // 明细更新时间
+
+ public bool MatchExtra(string? compareFields, string? extra)
+ {
+ // 匹配字段为空,明细明细字段为空
+ if (string.IsNullOrWhiteSpace(compareFields))
+ return string.IsNullOrWhiteSpace(CompareFields);
+
+ if (string.IsNullOrWhiteSpace(CompareFields))
+ return false;
+
+ if (!string.Equals(CompareFields, compareFields)) //todo:当比较字段存放到轨迹明细中,后面修改了比较字段后会发生什么?
+ return false;
+
+ if (string.IsNullOrEmpty(extra) || string.IsNullOrEmpty(Extra))
+ return false;
+
+ return TextJsonHelper.EqJsonStringField(extra, Extra, compareFields);
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningRetryPushTaskEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningRetryPushTaskEntity.cs
new file mode 100644
index 00000000..73c626dc
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningRetryPushTaskEntity.cs
@@ -0,0 +1,41 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+
+// 预警重试推送任务
+[SugarTable("t_warning_return_retry_task", TableDescription = "回传预警重试推送任务")]
+public sealed class ReturnWarningRetryPushTaskEntity : IFullAuditedBasicEntitys, IEntity
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "OrderId", ColumnDescription = "订单Id")]
+ public int OrderId { get; set; }
+
+ [SugarColumn(ColumnName = "WarningDetailId", ColumnDescription = "预警明细id")]
+ public string WarningDetailId { get; set; } //预警明细id
+
+ // 轨迹明细
+ [SugarColumn(ColumnName = "TrackCode", ColumnDescription = "轨迹code")]
+ public string TrackCode { get; set; }
+
+ [SugarColumn(ColumnName = "TrackContent", ColumnDescription = "轨迹内容")]
+ public string TrackContent { get; set; }
+
+ [SugarColumn(ColumnName = "CompareFields", ColumnDescription = "比较字段")]
+ public string? CompareFields { get; set; } //轨迹明细中的比较字段
+
+ [SugarColumn(ColumnName = "Extra", ColumnDescription = "扩展字段")]
+ public string? Extra { get; set; } //轨迹明细中的扩展字段
+
+
+ [SugarColumn(ColumnName = "OptionType", ColumnDescription = "操作类型")]
+ public string OptionType { get; set; } //操作类型,
+
+ [SugarColumn(ColumnName = "ServiceProviderCode", ColumnDescription = "服务商code")]
+ public string ServiceProviderCode { get; set; } //服务商code
+
+ [SugarColumn(ColumnName = "PushContent", ColumnDescription = "推送内容")]
+ public string PushContent { get; set; } //推送数据的序列化值,为TrackPushInput/TrackUpdateInput集合
+
+ [SugarColumn(ColumnName = "IsClosed", ColumnDescription = "是否关闭")]
+ public bool IsClosed { get; set; } // 已关闭的任务不会在执行
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningRuleItemEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningRuleItemEntity.cs
new file mode 100644
index 00000000..8f734a61
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Return/ReturnWarningRuleItemEntity.cs
@@ -0,0 +1,47 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
+
+// 回传预警规则项
+[SugarTable("t_warning_return_rule_item", TableDescription = "回传预警规则项")]
+public sealed class ReturnWarningRuleItemEntity : IFullAuditedBasicEntitys, IEntity
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "WarningId", ColumnDescription = "预警规则主体id")]
+ public int WarningId { get; set; }
+
+ [SugarColumn(ColumnName = "TrackStatusIds", ColumnDescription = "关注的轨迹状态Id集合")]
+ public string TrackStatusIds { get; set; } //关注的轨迹状态Id,可以是多个使用,分割
+
+ [SugarColumn(ColumnName = "ReturnTimeSpan", ColumnDescription = "时效(单位小时)")]
+ public float ReturnTimeSpan { get; set; } //时效(单位小时),只是用于判断状态
+
+ // [SugarColumn(ColumnName = "NotifyModes", ColumnDescription = "通知方式,多个方式(,)分割 eg: 1,2")]
+ // public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+
+ [SugarColumn(ColumnName = "NotifyUsers", ColumnDescription = "通知人Json eg: [{\"UserId\":1,\"UserName\":\"张三\"},{\"UserId\":2,\"UserName\":\"李四\"}]")]
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+
+ public ReturnWarningRuleItemEntity()
+ {
+ }
+
+ public ReturnWarningRuleItemEntity(int id, int warningId,string trackStatusIds, float returnTimeSpan, string notifyUsers)
+ {
+ Id = id;
+ WarningId = warningId;
+ TrackStatusIds = trackStatusIds;
+ ReturnTimeSpan = returnTimeSpan;
+ NotifyUsers = notifyUsers;
+ }
+
+ public HashSet GetRuleStatusIds()
+ {
+ return TrackStatusIds.Split(',').Select(int.Parse).ToHashSet();
+ }
+
+ public bool CanHitRule(int trackStatusId)
+ {
+ return GetRuleStatusIds().Contains(trackStatusId);
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/IWarningSignal.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/IWarningSignal.cs
new file mode 100644
index 00000000..d4fe7cbd
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/IWarningSignal.cs
@@ -0,0 +1,16 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+
+public interface IWarningSignal
+{
+ public int OrderId { get; set; }
+ public WarningSignalType Type { get; set; }
+}
+
+public enum WarningSignalType
+{
+ 轨迹新增 = 0,
+
+ 轨迹删除 = 1,
+
+ 轨迹更新 = 2,
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackAddedSignal.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackAddedSignal.cs
new file mode 100644
index 00000000..6e3f2bcf
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackAddedSignal.cs
@@ -0,0 +1,13 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+
+///
+/// 轨迹新增信号
+///
+public sealed class TrackAddedSignal : IWarningSignal
+{
+ public WarningSignalType Type { get; set; } = WarningSignalType.轨迹新增;
+
+ public int OrderId { get; set; }
+
+ public string EsId { get; set; } //新增轨迹的esId
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackDeletedSignal.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackDeletedSignal.cs
new file mode 100644
index 00000000..564669a2
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackDeletedSignal.cs
@@ -0,0 +1,15 @@
+using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+
+///
+/// 轨迹删除信号
+///
+public class TrackDeletedSignal : IWarningSignal
+{
+ public WarningSignalType Type { get; set; } = WarningSignalType.轨迹删除;
+
+ public int OrderId { get; set; }
+
+ public TrackDetailsIndex DeletedTrack { get; set; } //已删除的轨迹
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackUpdatedSignal.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackUpdatedSignal.cs
new file mode 100644
index 00000000..dd0e25be
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Signals/TrackUpdatedSignal.cs
@@ -0,0 +1,16 @@
+using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
+
+
+///
+/// 轨迹更新信号
+///
+public class TrackUpdatedSignal:IWarningSignal
+{
+ public WarningSignalType Type { get; set; } = WarningSignalType.轨迹更新;
+
+ public int OrderId { get; set; }
+
+ public TrackDetailsIndex BeforeChangeTrack { get; set; } //更改前的轨迹明细
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsGenerateTaskEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsGenerateTaskEntity.cs
new file mode 100644
index 00000000..4ce986e7
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsGenerateTaskEntity.cs
@@ -0,0 +1,44 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+
+[SugarTable("t_warning_transport_generate_task", TableDescription = "运输时效预警明细生成任务")]
+[SugarIndex("IDX_IsClosed_PlanExecutionTime", nameof(IsClosed), OrderByType.Desc, nameof(PlanExecutionTime), OrderByType.Asc)]
+public sealed class TransportWarningDetailsGenerateTaskEntity : IFullAuditedBasicEntitys, IEntity
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "OrderId", ColumnDescription = "订单Id")]
+ public int OrderId { get; set; }
+
+ [SugarColumn(ColumnName = "WarningId", ColumnDescription = "预警主体Id")]
+ public int WarningId { get; set; }
+
+ [SugarColumn(ColumnName = "WarningSceneId", ColumnDescription = "运输时效场景Id")]
+ public int WarningSceneId { get; set; }
+
+ [SugarColumn(ColumnName = "WarningSceneRuleItemId", ColumnDescription = "运输时效预警规则项Id")]
+ public int WarningSceneRuleItemId { get; set; } //运输时效预警规则项目Id
+
+
+ [SugarColumn(ColumnName = "StartTrackStatusId", ColumnDescription = "起始轨迹状态Id")]
+ public int StartTrackStatusId { get; set; } //起始轨迹状态Id
+
+ [SugarColumn(ColumnName = "EndTrackStatusId", ColumnDescription = "截止轨迹状态Id")]
+ public int EndTrackStatusId { get; set; } //截止轨迹状态Id
+
+ [SugarColumn(ColumnName = "StartTrackTime", ColumnDescription = "起始轨迹发生时间")]
+ public DateTime StartTrackTime { get; set; } //起始轨迹发生时间
+
+ [SugarColumn(ColumnName = "StartTrackTimeZone", ColumnDescription = "起始轨迹发生时区")]
+ public float StartTrackTimeZone { get; set; } //起始轨迹发生时区
+
+ [SugarColumn(ColumnName = "StartTrackWarningTimeSpan", ColumnDescription = "起始轨迹生成预警时间")]
+ public float StartTrackWarningTimeSpan { get; set; } //起始轨迹生成预警时间 (单位小时)
+
+ [SugarColumn(ColumnName = "PlanExecutionTime", ColumnDescription = "计划执行时间")]
+ public DateTime PlanExecutionTime { get; set; } //计划执行时间 tips:缓存【起始轨迹发生时间】+【起始轨迹生成预警时间】 结果,用于查询时过滤
+
+
+ [SugarColumn(ColumnName = "IsClosed", ColumnDescription = "是否关闭")]
+ public bool IsClosed { get; set; } //是否关闭,执行完成被关闭/手动关闭
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs
new file mode 100644
index 00000000..3d66b23a
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningDetailsIndex.cs
@@ -0,0 +1,144 @@
+using System.Collections.Immutable;
+using System.Text;
+using Nest;
+using SJZY.Expand.ElasticSearch;
+using SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
+using SJZY.Track.Domain.Consts;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+
+// 运输时效预警明细
+[ElasticsearchType(RelationName = GlobalConst.TransportWarningDetailsIndex)]
+public sealed class TransportWarningDetailsIndex : IdBaseIndex
+{
+ public string IndexName { get; set; }
+ public int WarningId { get; set; }
+ public int WarningSceneId { get; set; }
+ public int WarningSceneRuleItemId { get; set; }
+ public string Version { get; set; } //预警版本号
+
+ public string WarningName { get; set; } //(冗余)预警规则名称,规则主体名称
+ public string WarningRuleDescription { get; set; } // 预警规则描述 (场景+场景规则项目构建)
+
+ public float TransportTimeSpan { get; set; } //时效 (单位小时),用于计算状态
+ public float StartTrackWarningTimeSpan { get; set; } //起始轨迹生成预警时间 (单位小时),用于计算状态
+ //public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+
+ //订单信息
+ public int SubSystemId { get; set; } //(冗余)子系统Id
+ public string SubSystemName { get; set; } //(冗余)子系统名称
+ public int CustomId { get; set; } //(冗余)客户Id
+ public string CustomName { get; set; } //冗余 客户简称(用于查询条件)
+ public int OrderId { get; set; }
+ public string OrderNo { get; set; } //订单号
+ public int OrderType { get; set; } //(冗余)订单类型
+ public string OrderTypeName { get; set; } //(冗余)订单类型名称
+
+ //轨迹信息-起始(更新用例:新增轨迹时,场景/规则项变更并且重新命中)
+ public int StartTrackStatusId { get; set; } //起始轨迹状态Id
+ public string StartTrackStatus { get; set; } //(冗余)起始轨迹状态名称
+ public int StartTrackContentId { get; set; } //起始轨迹内容Id
+ public string StartTrackContent { get; set; } //(冗余)起始轨迹内容名称
+ public DateTime StartTrackTime { get; set; } //起始轨迹发生时间
+ public float StartTrackTimeZone { get; set; } //起始轨迹发生时区
+
+ //轨迹信息-截止(更新用例:新增轨迹时)
+ public int EndTrackStatusId { get; set; } //截止轨迹状态Id
+ public string EndTrackStatus { get; set; } //(冗余)截止轨迹状态名称
+ public int? EndTrackContentId { get; set; } //截止轨迹内容Id
+ public string? EndTrackContent { get; set; } //(冗余)截止轨迹内容名称
+ public DateTime? EndTrackTime { get; set; } //截止轨迹发生时间
+ public float? EndTrackTimeZone { get; set; } //截止轨迹发生时区
+
+ // // 实时属性 todo:后面拆出vo
+ // public int LatestTrackContentId { get; set; } //最新轨迹内容Id
+ // public string LatestTrackContent { get; set; } //(冗余)最新轨迹内容名称
+ // public DateTime LatestTrackTime { get; set; } //最新轨迹发生时间
+ // public float LatestTrackTimeZone { get; set; } //最新轨迹发生时区
+ // public string LatestTrackPlace { get; set; } //最新轨迹发生地
+
+
+ //计算属性
+ public long CumulativeTimeSpan { get; set; } //累计运输时间:当前时间-起始轨迹状态中的最早轨迹发生时间(利用 轨迹信息-起始 完成计算)单位(毫秒)
+ public int Status { get; set; } //1:即将超时 2:已超时 3:已完成 4:超时完成 5:已关闭,初始为【即将超时】
+
+ //审计属性
+ public DateTime CreateTime { get; set; } //预警创建时间
+
+ private static readonly ImmutableHashSet CompletedStatus = ImmutableHashSet.Create(3, 4, 5);
+
+ // todo:计算并设置状态,后续维护到vo当中
+ public int CalcStatus()
+ {
+ // 结束态无需计算,直接返回
+ if (CompletedStatus.Contains(Status)) return Status;
+
+ //时效
+ var transportTimeSpan = TimeSpan.FromHours(TransportTimeSpan); //小时
+ //累计运输时间
+ var cumulativeTimeSpan = TimeSpan.FromMilliseconds(CumulativeTimeSpan); //毫秒
+ //预警时效(预警发出的时间对比于最早轨迹状态时间的跨度)
+ var startTrackWarningTimeSpan = TimeSpan.FromHours(StartTrackWarningTimeSpan); //小时
+
+ //时效>累计运输时间>=预警时效 状态调整为【即将超时】
+ if (transportTimeSpan > cumulativeTimeSpan && cumulativeTimeSpan >= startTrackWarningTimeSpan)
+ return Status = 1;
+
+ //时效<累计运输时间 状态调整为【已超时】
+ if (transportTimeSpan < cumulativeTimeSpan)
+ return Status = 2;
+
+ return Status;
+ }
+
+ // 预警规则描述,创建预警明细,更新场景(需要重新匹配),更新规则项目(需要重新匹配),更新规则区域名称
+ // todo:缺失更新规则区域名称目前不被感知,出现预警明细和对于的规则区域名称不一致
+ // todo:转化为bo的使用
+ public string GetWarningRuleDescription(TransportWarningSceneEntity scene, TransportWarningSceneRuleItemEntity ruleItem, RuleAreaEntity? ruleArea)
+ {
+ var res = new StringBuilder("{");
+ // 起始轨迹状态-截止轨迹状态
+ res.Append($"{StartTrackStatus}-{EndTrackStatus}");
+
+ // 货物类型 (普货/危险品/...)
+ if (!string.IsNullOrWhiteSpace(scene.CargoType))
+ res.Append($",{scene.CargoType}");
+ // 月份 (1/3/5/...)
+ if (!string.IsNullOrWhiteSpace(scene.Months))
+ res.Append($",{scene.Months}");
+ // 区域名称 (美国xxx区域)
+ if (ruleArea != null)
+ res.Append($",{ruleArea.Name}");
+ // 是否中转(中转/直飞)
+ if (scene.IsTransit != null)
+ res.Append($",{(scene.IsTransit ?? false ? "中转" : "直飞")}");
+ // 出发港(xxx港)
+ if (!string.IsNullOrWhiteSpace(scene.LeavePort))
+ res.Append($",{scene.LeavePort}");
+ // 产品代码(xxx)
+ if (!string.IsNullOrWhiteSpace(scene.ProductCode))
+ res.Append($",{scene.ProductCode}");
+
+ // 规则配置信息
+ res.Append($",生成预警时间{ruleItem.StartTrackWarningTimeSpan}小时" +
+ $",提醒时效{ruleItem.TransportTimeSpan}}}");
+
+ return res.ToString();
+ }
+
+ public DateTime GetUtc0StartTrackTime()
+ {
+ return Math.Abs(StartTrackTimeZone - GlobalConst.NoneTrackTimeZone) < 0.1f
+ ? StartTrackTime
+ : StartTrackTime.Subtract(TimeSpan.FromHours(StartTrackTimeZone));
+ }
+
+ public DateTime? GetUtc0EndTrackTime()
+ {
+ if (EndTrackTime == null || EndTrackTimeZone == null) return null;
+ return Math.Abs(EndTrackTimeZone.Value - GlobalConst.NoneTrackTimeZone) < 0.1f
+ ? EndTrackTime
+ : EndTrackTime.Value.Subtract(TimeSpan.FromHours(EndTrackTimeZone.Value));
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningSceneEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningSceneEntity.cs
new file mode 100644
index 00000000..2239ebbe
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningSceneEntity.cs
@@ -0,0 +1,48 @@
+
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+
+// 运输时效场景
+[SugarTable("t_warning_transport_scene", TableDescription = "运输时效规则场景")]
+public sealed class TransportWarningSceneEntity : IFullAuditedBasicEntitys, IEntity
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "WarningId", ColumnDescription = "预警规则id")]
+ public int WarningId { get; set; }
+
+ [SugarColumn(ColumnName = "IsTransit", ColumnDescription = "是否中转")]
+ public bool? IsTransit { get; set; } //是否中转
+
+ [SugarColumn(ColumnName = "CargoType", ColumnDescription = "货物类型")]
+ public string? CargoType { get; set; } //货物类型,
+
+ [SugarColumn(ColumnName = "LeavePort", ColumnDescription = "起运港口")]
+ public string? LeavePort { get; set; } //起运港口
+
+ [SugarColumn(ColumnName = "ProductCode", ColumnDescription = "产品编码")]
+ public string? ProductCode { get; set; } //产品编码
+
+ [SugarColumn(ColumnName = "Months", ColumnDescription = "月份")]
+ public string? Months { get; set; } //月份, 1/2/3
+
+ [SugarColumn(ColumnName = "AreaId", ColumnDescription = "区域id")]
+ public int? AreaId { get; set; } //区域Id,单分区
+
+ public TransportWarningSceneEntity()
+ {
+ }
+
+ public TransportWarningSceneEntity(int id, int warningId, string? cargoType, string? months, int? areaId, bool? isTransit, string? leavePort, string? productCode)
+ {
+ Id = id;
+ WarningId = warningId;
+ CargoType = cargoType;
+ Months = months;
+ AreaId = areaId;
+ IsTransit = isTransit;
+ LeavePort = leavePort;
+ ProductCode = productCode;
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningSceneRuleItemEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningSceneRuleItemEntity.cs
new file mode 100644
index 00000000..ffb8db44
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/Transport/TransportWarningSceneRuleItemEntity.cs
@@ -0,0 +1,62 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
+
+// 运输时效场景规则项
+[SugarTable("t_warning_transport_scene_rule_item", TableDescription = "运输时效规则场景规则项")]
+public sealed class TransportWarningSceneRuleItemEntity : IFullAuditedBasicEntitys, IEntity
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "WarningId", ColumnDescription = "预警规则id")]
+ public int WarningId { get; set; }
+
+ [SugarColumn(ColumnName = "TransportWarningSceneId", ColumnDescription = "运输场景id")]
+ public int TransportWarningSceneId { get; set; }
+
+ [SugarColumn(ColumnName = "StartTrackStatusId", ColumnDescription = "起始轨迹状态Id")]
+ public int StartTrackStatusId { get; set; } //起始轨迹状态Id,tips:用于匹配轨迹
+
+ [SugarColumn(ColumnName = "EndTrackStatusId", ColumnDescription = "截止轨迹状态Id")]
+ public int EndTrackStatusId { get; set; } //截止轨迹状态Id, tips:用于验证预警明细是否可以产生,预警通知是否可以进行
+
+ [SugarColumn(ColumnName = "TransportTimeSpan", ColumnDescription = "时效 (单位小时)")]
+ public float TransportTimeSpan { get; set; } //时效 (单位小时)
+
+ [SugarColumn(ColumnName = "StartTrackWarningTimeSpan", ColumnDescription = "起始轨迹生成预警时间 (单位小时)")]
+ public float StartTrackWarningTimeSpan { get; set; } //起始轨迹生成预警时间 (单位小时)
+
+ // [SugarColumn(ColumnName = "NotifyModes", ColumnDescription = "通知方式,多个方式(,)分割 eg: 1,2")]
+ // public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+
+ [SugarColumn(ColumnName = "NotifyUsers", ColumnDescription = "通知人Json eg: [{\"UserId\":1,\"UserName\":\"张三\"},{\"UserId\":2,\"UserName\":\"李四\"}]")]
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+
+ public TransportWarningSceneRuleItemEntity()
+ {
+ }
+
+ public TransportWarningSceneRuleItemEntity(int id, int warningId, int transportWarningSceneId, int startTrackStatusId, int endTrackStatusId, float transportTimeSpan, float startTrackWarningTimeSpan, string notifyUsers)
+ {
+ Id = id;
+ WarningId = warningId;
+ TransportWarningSceneId = transportWarningSceneId;
+ StartTrackStatusId = startTrackStatusId;
+ EndTrackStatusId = endTrackStatusId;
+ TransportTimeSpan = transportTimeSpan;
+ StartTrackWarningTimeSpan = startTrackWarningTimeSpan;
+ NotifyUsers = notifyUsers;
+ }
+
+ public bool CanHitRule(int trackStatusId, HashSet trackStatusIds)
+ {
+ return trackStatusId == StartTrackStatusId //命中起始轨迹状态
+ && !trackStatusIds.Contains(EndTrackStatusId); //缺失截止轨迹状态
+ }
+
+ // 重新命中,用于规则扫描
+ public bool CanReHit(HashSet trackStatusIds)
+ {
+ return trackStatusIds.Contains(StartTrackStatusId) //存在起始
+ && !trackStatusIds.Contains(EndTrackStatusId); //不存在截止
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/WarningNotifyTaskEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/WarningNotifyTaskEntity.cs
new file mode 100644
index 00000000..bf57036b
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/WarningNotifyTaskEntity.cs
@@ -0,0 +1,56 @@
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate;
+
+[SugarTable("t_warning_notify_task", TableDescription = "预警通知任务")]
+public sealed class WarningNotifyTaskEntity : IFullAuditedBasicEntitys, IAggregateRoot
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "OrderId", ColumnDescription = "订单Id")]
+ public int OrderId { get; set; } //(冗余)订单id
+
+ [SugarColumn(ColumnName = "WarningId", ColumnDescription = "预警主体Id")]
+ public int WarningId { get; set; } // 预警Id
+
+ [SugarColumn(ColumnName = "WarningRuleId", ColumnDescription = "预警规则Id")]
+ public int WarningRuleId { get; set; } // 预警规则项目Id
+
+ [SugarColumn(ColumnName = "WarningDetailsId", ColumnDescription = "预警明细Id")]
+ public string WarningDetailsId { get; set; } //预警明细id
+
+ [SugarColumn(ColumnName = "AuxiliaryId", ColumnDescription = "辅助id,用于过滤匹配")]
+ public string? AuxiliaryId { get; set; } //辅助标识,用于增强匹配(例如运输时效预警有会有不同场景,可以通过这个字段完成匹配)
+
+ [SugarColumn(ColumnName = "WarningType", ColumnDescription = "预警类型,1:运输时效,2:回传时效,3:完整预警")]
+ public int WarningType { get; set; } // 预警类型,1:运输时效,2:回传时效,3:完整预警
+
+ // [SugarColumn(ColumnName = "NotifyModes", ColumnDescription = "通知方式,多个方式(,)分割 eg: 1,2")]
+ // public string NotifyModes { get; set; } //通知方式,多个方式(,)分割 eg: 1,2
+
+ [SugarColumn(ColumnName = "NotifyUsers", ColumnDescription = "通知人Json eg: [{\"UserId\":1,\"UserName\":\"张三\"},{\"UserId\":2,\"UserName\":\"李四\"}]")]
+ public string NotifyUsers { get; set; } //通知人Json eg: [{"UserId":1,"UserName":"张三"},{"UserId":2,"UserName":"李四"}]
+
+
+ [SugarColumn(ColumnName = "Tags", ColumnDescription = "标签集合(,分割)")]
+ public string? Tags { get; set; } // 标签(加急?)
+
+ [SugarColumn(ColumnName = "IsClosed", ColumnDescription = "是否关闭")]
+ public bool IsClosed { get; set; } //是否已经关闭,使用时过滤已关闭的通知任务
+
+ public WarningNotifyTaskEntity()
+ {
+ }
+
+ public WarningNotifyTaskEntity(int orderId, int warningId, int warningRuleId, string warningDetailsId, int warningType, string notifyUsers, string? tags = null)
+ {
+ OrderId = orderId;
+ WarningId = warningId;
+ WarningRuleId = warningRuleId;
+ WarningDetailsId = warningDetailsId;
+ WarningType = warningType;
+ NotifyUsers = notifyUsers;
+ Tags = tags;
+ CreateTime = DateTime.Now;
+ IsClosed = false;
+ }
+}
diff --git a/src/SJZY.Track.Domain/Aggregates/WarningAggregate/WarningRuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/WarningRuleEntity.cs
new file mode 100644
index 00000000..fc4ae6c1
--- /dev/null
+++ b/src/SJZY.Track.Domain/Aggregates/WarningAggregate/WarningRuleEntity.cs
@@ -0,0 +1,66 @@
+using SJZY.Track.Domain.Extensions;
+
+namespace SJZY.Track.Domain.Aggregates.WarningAggregate;
+
+// 预警规则主体
+[SugarTable("t_warning_0", TableDescription = "预警规则主体(用于将来替换t_warning)")]
+public sealed class WarningRuleEntity : IFullAuditedBasicEntitys, IAggregateRoot
+{
+ [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
+ public int Id { get; set; }
+
+ [SugarColumn(ColumnName = "SubSystemId", ColumnDescription = "子系统id")]
+ public int SubSystemId { get; set; } //子系统id
+
+ [SugarColumn(ColumnName = "CustomId", ColumnDescription = "客户id")]
+ public int CustomId { get; set; } //客户id
+
+ // [SugarColumn(ColumnName = "CustomName", ColumnDescription = "客户名称")]
+ // public string CustomName { get; set; } //冗余客户简称,用于查询
+
+ [SugarColumn(ColumnName = "Name", ColumnDescription = "预警规则名称")]
+ public string Name { get; set; } //预警规则名称
+
+ [SugarColumn(ColumnName = "IsEnabled", ColumnDescription = "是否启用")]
+ public bool IsEnabled { get; set; }
+
+ [SugarColumn(ColumnName = "WarningType", ColumnDescription = "预警类型,1:运输时效,2:回传时效,3:完整预警")]
+ public int WarningType { get; set; } //预警类型,1:运输时效,2:回传时效,3:完整预警
+
+ [SugarColumn(ColumnName = "Version", ColumnDescription = "规则版本,用于标识规则产物(如预警信息)")]
+ public string Version { get; set; } //规则版本,用于标识规则产物(如预警信息)
+
+
+ public WarningRuleEntity()
+ {
+ }
+
+
+ public WarningRuleEntity(int id, string name, int subSystemId, int customId, bool isEnabled, int warningType, string version)
+ {
+ Id = id;
+ Name = name;
+ SubSystemId = subSystemId;
+ CustomId = customId;
+ IsEnabled = isEnabled;
+ WarningType = warningType;
+ Version = version;
+ }
+
+ public WarningRuleEntity(int id, string name, int subSystemId, int customId, bool isEnabled, int warningType)
+ {
+ Id = id;
+ Name = name;
+ SubSystemId = subSystemId;
+ CustomId = customId;
+ IsEnabled = isEnabled;
+ WarningType = warningType;
+ Version = VersionGenerate.GenVersion();
+ }
+
+ // 子系统+客户id确定命中规则主体
+ public bool CanHitRule(int subSystemId, int customId)
+ {
+ return SubSystemId == subSystemId && CustomId == customId;
+ }
+}
diff --git a/src/SJZY.Track.Domain/Dtos/Warning/GetPageCompleteWarningDetailsInputVO.cs b/src/SJZY.Track.Domain/Dtos/Warning/GetPageCompleteWarningDetailsInputVO.cs
new file mode 100644
index 00000000..2f0682f0
--- /dev/null
+++ b/src/SJZY.Track.Domain/Dtos/Warning/GetPageCompleteWarningDetailsInputVO.cs
@@ -0,0 +1,60 @@
+namespace SJZY.Track.Domain.Dtos.Warning;
+
+public class GetPageCompleteWarningDetailsInputVO : PageInfoInput
+{
+ ///
+ /// 子系统id
+ ///
+ public int? SubSystemId { get; set; }
+
+ ///
+ /// 订单号,多个订单号(,分割)
+ ///
+ public string? OrderNos { get; set; }
+
+ ///
+ /// 订单类型
+ ///
+ public int? OrderType { get; set; }
+
+ ///
+ /// 状态
+ /// 1:待处理,2:已处理,3:已关闭
+ ///
+ public int? Status { get; set; }
+
+ ///
+ /// 客户id
+ ///
+ public int? CustomId { get; set; }
+
+ ///
+ /// 缺失轨迹状态id
+ ///
+ public int? MissingTrackStatusId { get; set; }
+
+ ///
+ /// 通知对象id
+ ///
+ public int? NotifyUserId { get; set; }
+
+ ///
+ /// 预警创建时间开始
+ ///
+ public DateTime? WarningCreateTimeStart { get; set; }
+
+ ///
+ /// 预警创建时间截止
+ ///
+ public DateTime? WarningCreateTimeEnd { get; set; }
+
+ ///
+ /// 预警处理时间开始
+ ///
+ public DateTime? WarningHandleTimeStart { get; set; }
+
+ ///
+ /// 预警处理时间截止
+ ///
+ public DateTime? WarningHandleTimeEnd { get; set; }
+}
diff --git a/src/SJZY.Track.Domain/Dtos/Warning/GetPageReturnWarningDetailsInputVO.cs b/src/SJZY.Track.Domain/Dtos/Warning/GetPageReturnWarningDetailsInputVO.cs
new file mode 100644
index 00000000..aceaacf1
--- /dev/null
+++ b/src/SJZY.Track.Domain/Dtos/Warning/GetPageReturnWarningDetailsInputVO.cs
@@ -0,0 +1,93 @@
+namespace SJZY.Track.Domain.Dtos.Warning;
+
+///
+/// 分页获取回传预警明细输入
+///
+public class GetPageReturnWarningDetailsInputVO : PageInfoInput
+{
+ ///
+ /// 子系统id
+ ///
+ public int? SubSystemId { get; set; }
+
+ ///
+ /// 订单号,多个订单号(,分割)
+ ///
+ public string? OrderNos { get; set; }
+
+ ///
+ /// 订单类型
+ ///
+ public int? OrderType { get; set; }
+
+ ///
+ /// 状态
+ /// 1:人工介入 2:重试中 3:推送完成 4:已关闭
+ ///
+ public int? Status { get; set; }
+
+ ///
+ /// 客户id
+ ///
+ public int? CustomId { get; set; }
+
+ ///
+ /// 轨迹状态id
+ ///
+ public int? TrackStatusId { get; set; }
+
+ ///
+ /// 轨迹内容id
+ ///
+ public int? TrackContentId { get; set; }
+
+ ///
+ /// 是否有Kpi考核 (传null为查全部)
+ ///
+ public bool? IsKpi { get; set; }
+
+ ///
+ /// 通知对象用户id
+ ///
+ public int? NotifyUserId { get; set; }
+
+ ///
+ /// 轨迹发生时间开始
+ ///
+ public DateTime? TrackTimeStart { get; set; }
+
+ ///
+ /// 轨迹发生时间截止
+ ///
+ public DateTime? TrackTimeEnd { get; set; }
+
+ ///
+ /// 轨迹创建时间开始
+ ///
+ public DateTime? TrackCreateTimeStart { get; set; }
+
+ ///
+ /// 轨迹创建时间截止
+ ///
+ public DateTime? TrackCreateTimeEnd { get; set; }
+
+ ///
+ /// 轨迹回传时间开始
+ ///
+ public DateTime? TrackReturnTimeStart { get; set; }
+
+ ///
+ /// 轨迹回传时间截止
+ ///
+ public DateTime? TrackReturnTimeEnd { get; set; }
+
+ ///
+ /// 预警创建时间开始
+ ///
+ public DateTime? WarningCreateTimeStart { get; set; }
+
+ ///
+ /// 预警创建时间截止
+ ///
+ public DateTime? WarningCreateTimeEnd { get; set; }
+}
diff --git a/src/SJZY.Track.Domain/Dtos/Warning/GetPageTransportWarningDetailsInputVO.cs b/src/SJZY.Track.Domain/Dtos/Warning/GetPageTransportWarningDetailsInputVO.cs
new file mode 100644
index 00000000..6fecc8aa
--- /dev/null
+++ b/src/SJZY.Track.Domain/Dtos/Warning/GetPageTransportWarningDetailsInputVO.cs
@@ -0,0 +1,52 @@
+namespace SJZY.Track.Domain.Dtos.Warning;
+
+///
+/// 分页获取运输预警明细
+///
+public class GetPageTransportWarningDetailsInputVO : PageInfoInput
+{
+ ///
+ /// 子系统id
+ ///
+ public int? SubSystemId { get; set; }
+
+ ///
+ /// 订单号,多个订单号(,分割)
+ ///
+ public string? OrderNos { get; set; }
+
+ ///
+ /// 订单类型
+ ///
+ public int? OrderType { get; set; }
+
+ ///
+ /// 状态
+ ///
+ public int? Status { get; set; }
+
+ ///
+ /// 客户Id
+ ///
+ public int? CustomId { get; set; }
+
+ ///
+ /// 预警名称
+ ///
+ public string? WarningName { get; set; }
+
+ ///
+ /// 通知对象用户Id
+ ///
+ public int? NotifyUserId { get; set; }
+
+ ///
+ /// 创建时间开始
+ ///
+ public DateTime? CreateTimeStart { get; set; }
+
+ ///
+ /// 创建时间截止
+ ///
+ public DateTime? CreateTimeEnd { get; set; }
+}
diff --git a/src/SJZY.Track.Domain/Enums/CompleteWarningStatus.cs b/src/SJZY.Track.Domain/Enums/CompleteWarningStatus.cs
new file mode 100644
index 00000000..943dccf7
--- /dev/null
+++ b/src/SJZY.Track.Domain/Enums/CompleteWarningStatus.cs
@@ -0,0 +1,8 @@
+namespace SJZY.Track.Domain.Enums;
+
+public enum CompleteWarningStatus
+{
+ 待处理 = 1,
+ 已处理 = 2,
+ 已关闭 = 3
+}
diff --git a/src/SJZY.Track.Domain/Enums/ReturnWarningStatus.cs b/src/SJZY.Track.Domain/Enums/ReturnWarningStatus.cs
new file mode 100644
index 00000000..a0d28b00
--- /dev/null
+++ b/src/SJZY.Track.Domain/Enums/ReturnWarningStatus.cs
@@ -0,0 +1,9 @@
+namespace SJZY.Track.Domain.Enums;
+
+public enum ReturnWarningStatus
+{
+ 人工介入 = 1,
+ 重试中 = 2,
+ 推送完成 = 3,
+ 已关闭 = 4
+}
diff --git a/src/SJZY.Track.Domain/Enums/TransportWarningStatus.cs b/src/SJZY.Track.Domain/Enums/TransportWarningStatus.cs
new file mode 100644
index 00000000..fe4d605d
--- /dev/null
+++ b/src/SJZY.Track.Domain/Enums/TransportWarningStatus.cs
@@ -0,0 +1,10 @@
+namespace SJZY.Track.Domain.Enums;
+
+public enum TransportWarningStatus
+{
+ 即将超时 = 1,
+ 已超时 = 2,
+ 已完成 = 3,
+ 超时完成 = 4,
+ 已关闭 = 5,
+}
diff --git a/src/SJZY.Track.Domain/Extensions/CollectionExtensions.cs b/src/SJZY.Track.Domain/Extensions/CollectionExtensions.cs
new file mode 100644
index 00000000..fc788ba9
--- /dev/null
+++ b/src/SJZY.Track.Domain/Extensions/CollectionExtensions.cs
@@ -0,0 +1,120 @@
+using System.Collections.Concurrent;
+using Nest;
+using SJZY.Expand.ElasticSearch;
+
+namespace SJZY.Track.Domain.Extensions;
+
+public class ListWrapperFactory
+{
+ public static ListWrapper, QueryContainer>> CreateListWrapper(TInput input)
+ where TIndex : IdBaseIndex
+ {
+ return new ListWrapper, QueryContainer>>(new (), input);
+ }
+}
+public class ListWrapper : List
+{
+ public List List { get; set; }
+ public TInput Input { get; set; }
+
+ public ListWrapper(List list, TInput input)
+ {
+ List = list;
+ Input = input;
+ }
+
+ public void AddIf(Predicate