feat:预警迭代初步

This commit is contained in:
hardstylewyl 2025-03-05 10:46:13 +08:00
parent 25298dc494
commit c44c4e3af2
77 changed files with 4984 additions and 497 deletions

View File

@ -3,104 +3,104 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Complete;
/// <summary>
/// 完整预警
/// </summary>
public class CompleteWarningDetailsDto // todo:需要根据状态排序
public class CompleteWarningDetailsDto
{
/// <summary>
/// 预警明细唯一id
/// </summary>
public string EsId { get; set; }
/// <summary>
/// 预警明细唯一id
/// </summary>
public string EsId { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 子系统名称
/// </summary>
public string SubSystemName { get; set; } // todo:id换名称
/// <summary>
/// 子系统名称
/// </summary>
public string SubSystemName { get; set; } // todo:id换名称
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 订单类型名称
/// </summary>
public string OrderTypeName { get; set; } // todo:type换名称
/// <summary>
/// 订单类型名称
/// </summary>
public string OrderTypeName { get; set; } // todo:type换名称
/// <summary>
/// 订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; }
/// <summary>
/// 状态 (待处理样式标红)
/// 1:待处理,2:已处理,3:已关闭
/// </summary>
public int Status { get; set; }
/// <summary>
/// 状态 (待处理样式标红)
/// 1:待处理,2:已处理,3:已关闭
/// </summary>
public int Status { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 客户简称
/// </summary>
public int CustomName { get; set; } // todo:id换名称
/// <summary>
/// 客户简称
/// </summary>
public string CustomName { get; set; }
/// <summary>
/// 缺失轨迹状态
/// </summary>
public string MissingTrackStatus { get; set; } // todo:id换名称
/// <summary>
/// 缺失轨迹状态
/// </summary>
public string MissingTrackStatus { get; set; } // todo:id换名称
//视图属性 todo:可以从订单主表拿到
//视图属性 tips:从es即时拿取
/// <summary>
/// 最新轨迹状态
/// </summary>
public string LatestTrackStatus { get; set; }
/// <summary>
/// 最新轨迹状态
/// </summary>
public string? LatestTrackStatus { get; set; }
/// <summary>
/// 最新轨迹内容
/// </summary>
public string LatestTrackContent { get; set; }
/// <summary>
/// 最新轨迹内容
/// </summary>
public string? LatestTrackContent { get; set; }
/// <summary>
/// 最新轨迹发生地
/// </summary>
public string LatestTrackPlace { get; set; }
/// <summary>
/// 最新轨迹发生地
/// </summary>
public string? LatestTrackPlace { get; set; }
/// <summary>
/// 最新轨迹发生时间
/// </summary>
public DateTime LatestTrackTime { get; set; }
/// <summary>
/// 最新轨迹发生时间
/// </summary>
public DateTime? LatestTrackTime { get; set; }
/// <summary>
/// 最新轨迹发生时区
/// </summary>
public float LatestTrackTimeZone { get; set; }
/// <summary>
/// 最新轨迹发生时区
/// </summary>
public float? LatestTrackTimeZone { get; set; }
/// <summary>
/// 通知对象
/// </summary>
public string NotifyUserNames { get; set; }
/// <summary>
/// 通知对象
/// </summary>
public string NotifyUserNames { get; set; }
/// <summary>
/// 预警创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 预警创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 预警处理时间
/// </summary>
public DateTime? ProcessedTime { get; set; }
/// <summary>
/// 预警处理时间
/// </summary>
public DateTime? ProcessedTime { get; set; }
}

View File

@ -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
/// <summary>
/// 订单类型 e.g FBA订单、海运单
/// </summary>
public List<OrderTypeDto> OrderType { get; set; }
public List<OrderTypeDto> OrderTypes { get; set; }
/// <summary>
/// 检查点轨迹状态id

View File

@ -8,16 +8,16 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Complete;
/// </summary>
public class EditCompleteWarningRuleItemInput
{
/// <summary>
/// 预警规主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警规主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警规则配置项目(列表内容传递)
/// </summary>
public List<EditCompleteWarningRuleItemDto> Items { get; set; } = new();
/// <summary>
/// 预警规则配置项目(列表内容传递)
/// </summary>
public List<EditCompleteWarningRuleItemDto> Items { get; set; } = new();
}
/// <summary>
@ -25,35 +25,35 @@ public class EditCompleteWarningRuleItemInput
/// </summary>
public class EditCompleteWarningRuleItemDto
{
/// <summary>
/// 规则项目唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 规则项目唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 订单类型集合(,分割) e.g. 1,2,3
/// </summary>
[Required]
public string OrderTypes { get; set; }
/// <summary>
/// 订单类型集合(,分割) e.g. 1,2,3
/// </summary>
[Required]
public string OrderTypes { get; set; }
/// <summary>
/// 检查点轨迹状态id
/// </summary>
[IdRequired]
public int CheckPointTrackStatusId { get; set; }
/// <summary>
/// 检查点轨迹状态id
/// </summary>
[IdRequired]
public int CheckPointTrackStatusId { get; set; }
/// <summary>
/// 要求的轨迹状态id集合 e.g. [[1,3],[5,7]]
/// required: 集合元素(子集合)不要有交集!
/// </summary>
[Required]
[MinLength(1, ErrorMessage = "要求的轨迹状态id集合不能为空")]
public List<List<int>> RequireTrackStatus { get; set; }
/// <summary>
/// 要求的轨迹状态id集合 e.g. [[1,3],[5,7]]
/// required: 集合元素(子集合)不要有交集!
/// </summary>
[Required]
[MinLength(1, ErrorMessage = "要求的轨迹状态id集合不能为空")]
public List<List<int>> RequireTrackStatus { get; set; }
/// <summary>
/// 通知对象用户集合
/// </summary>
[Required]
[MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
/// <summary>
/// 通知对象用户集合
/// </summary>
[Required]
[MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
}

View File

@ -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";
}
}

View File

@ -5,15 +5,15 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning;
public sealed class NotifyUserDto
{
/// <summary>
/// 用户id
/// </summary>
[IdRequired]
public int UserId { get; set; }
/// <summary>
/// 用户id
/// </summary>
[IdRequired]
public int UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required]
public string UserName { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required]
public string UserName { get; set; }
}

View File

@ -8,16 +8,16 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Return;
/// </summary>
public class EditReturnWarningRuleItemInput
{
/// <summary>
/// 预警规主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警规主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警规则配置项目(列表内容传递)
/// </summary>
public List<EditReturnWarningRuleItemDto> Items { get; set; } = new();
/// <summary>
/// 预警规则配置项目(列表内容传递)
/// </summary>
public List<EditReturnWarningRuleItemDto> Items { get; set; } = new();
}
/// <summary>
@ -25,26 +25,26 @@ public class EditReturnWarningRuleItemInput
/// </summary>
public class EditReturnWarningRuleItemDto
{
/// <summary>
/// 唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 轨迹状态Id集合(,分割)
/// </summary>
[Required]
public string TrackStatusIds { get; set; }
/// <summary>
/// 轨迹状态Id集合(,分割)
/// </summary>
[Required]
public string TrackStatusIds { get; set; }
/// <summary>
/// 时效(单位h)
/// </summary>
[Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
public float ReturnTimeSpan { get; set; }
/// <summary>
/// 时效(单位h)
/// </summary>
[Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
public float ReturnTimeSpan { get; set; }
/// <summary>
/// 通知对象用户集合
/// </summary>
[MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
/// <summary>
/// 通知对象用户集合
/// </summary>
[MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
}

View File

@ -2,7 +2,6 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Return;
/// <summary>
/// 回传预警明细
/// todo:需要根据状态排序
/// </summary>
public sealed class ReturnWarningDetailsDto
{
@ -17,7 +16,7 @@ public sealed class ReturnWarningDetailsDto
public int SubSystemId { get; set; }
/// <summary>
/// 子系统名称
/// 子系统名称
/// </summary>
public string SubSystemName { get; set; } // todo:id换名称
@ -27,7 +26,7 @@ public sealed class ReturnWarningDetailsDto
public int OrderType { get; set; }
/// <summary>
/// 订单类型名称
/// 订单类型名称
/// </summary>
public string OrderTypeName { get; set; } // todo:type换名称
@ -52,17 +51,17 @@ public sealed class ReturnWarningDetailsDto
public int CustomId { get; set; }
/// <summary>
/// 客户简称
/// 客户简称
/// </summary>
public string CustomName { get; set; } // todo:id换名称
public string CustomName { get; set; } // todo:id换名称
/// <summary>
/// 轨迹状态
/// 轨迹状态
/// </summary>
public string TrackStatus { get; set; }
/// <summary>
/// 轨迹代码
/// 轨迹代码
/// </summary>
public string TrackCode { get; set; }
@ -87,7 +86,7 @@ public sealed class ReturnWarningDetailsDto
public string PushTrackContent { get; set; }
/// <summary>
/// 轨迹发生地
/// 轨迹发生地
/// </summary>
public string TrackPlace { get; set; }
@ -112,7 +111,7 @@ public sealed class ReturnWarningDetailsDto
public DateTime? TrackReturnTime { get; set; }
/// <summary>
/// 回传时效
/// 回传时效 (单位h)
/// </summary>
public float? ReturnTimeSpan { get; set; }

View File

@ -5,22 +5,22 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
public class EditTransportWarningSceneRuleItemInput
{
/// <summary>
/// 预警规主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警规主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 运输预警场景id
/// </summary>
[IdRequired]
public int SceneId { get; set; }
/// <summary>
/// 运输预警场景id
/// </summary>
[IdRequired]
public int SceneId { get; set; }
/// <summary>
/// 预警规则配置项目(列表内容传递)
/// </summary>
public List<EditTransportWarningSceneRuleItemDto> Items { get; set; } = new();
/// <summary>
/// 预警规则配置项目(列表内容传递)
/// </summary>
public List<EditTransportWarningSceneRuleItemDto> Items { get; set; } = new();
}
/// <summary>
@ -28,38 +28,38 @@ public class EditTransportWarningSceneRuleItemInput
/// </summary>
public class EditTransportWarningSceneRuleItemDto
{
/// <summary>
/// 规则项目id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 规则项目id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 起始轨迹状态Id
/// </summary>
[IdRequired]
public int StartTrackStatusId { get; set; }
/// <summary>
/// 起始轨迹状态Id
/// </summary>
[IdRequired]
public int StartTrackStatusId { get; set; }
/// <summary>
/// 截止轨迹状态Id
/// </summary>
[IdRequired]
public int EndTrackStatusId { get; set; }
/// <summary>
/// 截止轨迹状态Id
/// </summary>
[IdRequired]
public int EndTrackStatusId { get; set; }
/// <summary>
/// 时效 (单位h)
/// </summary>
[Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
public float TransportTimeSpan { get; set; }
/// <summary>
/// 时效 (单位h)
/// </summary>
[Range(0.1, float.MaxValue, ErrorMessage = "时效必须大于0.1")]
public float TransportTimeSpan { get; set; }
/// <summary>
/// 起始轨迹生成预警时间 (单位h)
/// </summary>
[Range(0.1, float.MaxValue, ErrorMessage = "起始轨迹生成预警时间必须大于0.1")]
public float StartTrackWarningTimeSpan { get; set; }
/// <summary>
/// 起始轨迹生成预警时间 (单位h)
/// </summary>
[Range(0.1, float.MaxValue, ErrorMessage = "起始轨迹生成预警时间必须大于0.1")]
public float StartTrackWarningTimeSpan { get; set; }
/// <summary>
/// 通知对象用户集合
/// </summary>
[MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
/// <summary>
/// 通知对象用户集合
/// </summary>
[MinLength(1, ErrorMessage = "通知对象用户集合不能为空")]
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
}

View File

@ -7,9 +7,9 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
/// </summary>
public class GetTransportWarningSceneInput
{
/// <summary>
/// 预警主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
}

View File

@ -7,15 +7,15 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
/// </summary>
public class GetTransportWarningSceneRuleItemInput
{
/// <summary>
/// 预警主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 预警主体id
/// </summary>
[IdRequired]
public int WarningId { get; set; }
/// <summary>
/// 运输预警场景id
/// </summary>
[IdRequired]
public int SceneId { get; set; }
/// <summary>
/// 运输预警场景id
/// </summary>
[IdRequired]
public int SceneId { get; set; }
}

View File

@ -5,145 +5,145 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
/// </summary>
public sealed class TransportWarningDetailsDto // todo:需要根据状态排序
{
/// <summary>
/// 预警明细唯一id
/// </summary>
public string EsId { get; set; }
/// <summary>
/// 预警明细唯一id
/// </summary>
public string EsId { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 子系统名称
/// </summary>
public string SubSystemName { get; set; } // todo:id换名称
/// <summary>
/// 子系统名称
/// </summary>
public string SubSystemName { get; set; } // todo:id换名称
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 客户简称
/// </summary>
public string CustomName { get; set; } // todo:id换名称
/// <summary>
/// 客户简称
/// </summary>
public string CustomName { get; set; } // todo:id换名称
/// <summary>
/// 订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int OrderType { get; set; }
/// <summary>
/// 订单类型名称
/// </summary>
public string OrderTypeName { get; set; } // todo:type换名称
/// <summary>
/// 订单类型名称
/// </summary>
public string OrderTypeName { get; set; } // todo:type换名称
// 实时属性 todo:从订单查询
// 实时属性 todo:从es查询
/// <summary>
/// 最新轨迹内容
/// </summary>
public string LatestTrackContent { get; set; }
/// <summary>
/// 最新轨迹内容
/// </summary>
public string? LatestTrackContent { get; set; }
/// <summary>
/// 最新轨迹时间
/// </summary>
public DateTime LatestTrackTime { get; set; }
/// <summary>
/// 最新轨迹时间
/// </summary>
public DateTime? LatestTrackTime { get; set; }
/// <summary>
/// 最新轨迹发生时区
/// </summary>
public float LatestTrackTimeZone { get; set; }
/// <summary>
/// 最新轨迹发生时区
/// </summary>
public float? LatestTrackTimeZone { get; set; }
/// <summary>
/// 最新轨迹发生地
/// </summary>
public string LatestTrackPlace { get; set; }
/// <summary>
/// 最新轨迹发生地
/// </summary>
public string? LatestTrackPlace { get; set; }
/// <summary>
/// 通知对象
/// </summary>
public string NotifyUserNames { get; set; }
/// <summary>
/// 通知对象
/// </summary>
public string NotifyUserNames { get; set; }
/// <summary>
/// 起始轨迹状态
/// </summary>
public string StartTrackStatus { get; set; }
/// <summary>
/// 起始轨迹状态
/// </summary>
public string StartTrackStatus { get; set; }
/// <summary>
/// 起始轨迹内容
/// </summary>
public string StartTrackContent { get; set; }
/// <summary>
/// 起始轨迹内容
/// </summary>
public string StartTrackContent { get; set; }
/// <summary>
/// 起始轨迹发生时间
/// </summary>
public DateTime StartTrackTime { get; set; }
/// <summary>
/// 起始轨迹发生时间
/// </summary>
public DateTime StartTrackTime { get; set; }
/// <summary>
/// 起始轨迹时区
/// </summary>
public float StartTrackTimeZone { get; set; }
/// <summary>
/// 起始轨迹时区
/// </summary>
public float StartTrackTimeZone { get; set; }
/// <summary>
/// 截止轨迹状态
/// </summary>
public string EndTrackStatus { get; set; }
/// <summary>
/// 截止轨迹状态
/// </summary>
public string EndTrackStatus { get; set; }
/// <summary>
/// 截止轨迹内容
/// </summary>
public string? EndTrackContent { get; set; }
/// <summary>
/// 截止轨迹内容
/// </summary>
public string? EndTrackContent { get; set; }
/// <summary>
/// 截止轨迹发生时间
/// </summary>
public DateTime? EndTrackTime { get; set; }
/// <summary>
/// 截止轨迹发生时间
/// </summary>
public DateTime? EndTrackTime { get; set; }
/// <summary>
/// 截止轨迹时区
/// </summary>
public float? EndTrackTimeZone { get; set; }
/// <summary>
/// 截止轨迹时区
/// </summary>
public float? EndTrackTimeZone { get; set; }
/// <summary>
/// 预警名称 (预警主体名称 如字节全程时效)
/// </summary>
public string WarningName { get; set; }
/// <summary>
/// 预警名称 (预警主体名称 如字节全程时效)
/// </summary>
public string WarningName { get; set; }
/// <summary>
/// 预警规则描述(用于tooltip展示)
/// </summary>
public string WarningRuleDescription { get; set; }
/// <summary>
/// 预警规则描述(用于tooltip展示)
/// </summary>
public string WarningRuleDescription { get; set; }
/// <summary>
/// 累计运输时间
/// </summary>
public string CumulativeTimeSpan { get; set; } // todo:需要转换为某个格式
/// <summary>
/// 累计运输时间
/// </summary>
public string CumulativeTimeSpan { get; set; } // todo:需要转换为某个格式
/// <summary>
/// 预警状态 (根据key展示对应名称,即将超时需要标红)
/// 1:即将超时 2:已超时 3:已完成 4:超时完成 5:已关闭,初始为【即将超时】
/// </summary>
public int Status { get; set; }
/// <summary>
/// 预警状态 (根据key展示对应名称,即将超时需要标红)
/// 1:即将超时 2:已超时 3:已完成 4:超时完成 5:已关闭,初始为【即将超时】
/// </summary>
public int Status { get; set; }
/// <summary>
/// 预警创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 预警创建时间
/// </summary>
public DateTime CreateTime { get; set; }
}

View File

@ -16,7 +16,7 @@ public class TransportWarningSceneDto
public int WarningId { get; set; }
/// <summary>
/// 场景摘要(用于展示场景tabs)
/// 场景摘要(用于展示场景tabs)
/// </summary>
public string Summary { get; set; } // todo:将规则场景一些列因素转换为一段描述

View File

@ -1,5 +1,3 @@
using SJZY.Track.Application.Contract.Dtos.Warning;
namespace SJZY.Track.Application.Contract.Dtos.Warning.Transport;
/// <summary>
@ -46,4 +44,4 @@ public class TransportWarningSceneRuleItemDto
/// 通知对象用户集合
/// </summary>
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
}
}

View File

@ -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
{
/// <summary>
/// 场景唯一id (传0视为新增)

View File

@ -8,38 +8,38 @@ namespace SJZY.Track.Application.Contract.Dtos.Warning;
/// </summary>
public class UpsertWarningRuleInput
{
/// <summary>
/// 唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 子系统id
/// </summary>
[IdRequired]
public int SubSystemId { get; set; } //子系统id
/// <summary>
/// 子系统id
/// </summary>
[IdRequired]
public int SubSystemId { get; set; } //子系统id
/// <summary>
/// 客户id
/// </summary>
[IdRequired]
public int CustomId { get; set; } //客户id
/// <summary>
/// 客户id
/// </summary>
[IdRequired]
public int CustomId { get; set; } //客户id
/// <summary>
/// 预警规则名称
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 预警规则名称
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 是否启用
/// </summary>
[Required]
public bool IsEnabled { get; set; }
/// <summary>
/// 是否启用
/// </summary>
[Required]
public bool IsEnabled { get; set; }
/// <summary>
/// 预警类型,1:运输时效,2:回传时效,3:完整预警
/// </summary>
[Range(1, 3, ErrorMessage = "预警类型只能选取以下值,1:运输时效,2:回传时效,3:完整预警")]
public int WarningType { get; set; }
/// <summary>
/// 预警类型,1:运输时效,2:回传时效,3:完整预警
/// </summary>
[Range(1, 3, ErrorMessage = "预警类型只能选取以下值,1:运输时效,2:回传时效,3:完整预警")]
public int WarningType { get; set; }
}

View File

@ -13,22 +13,22 @@ public sealed class WarningRuleDto
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; } //子系统id
public int SubSystemId { get; set; } //子系统id
/// <summary>
/// 子系统名称
/// 子系统名称
/// </summary>
public int SubSystemName { get; set; } // todo:id换name
public string SubSystemName { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; } //客户id
public int CustomId { get; set; } //客户id
/// <summary>
/// 客户简称
/// 客户简称
/// </summary>
public int CustomName { get; set; } // todo:id换name
public string CustomName { get; set; }
/// <summary>
/// 预警规则名称

View File

@ -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<GetPageCompleteWarningDetailsInput, GetPageCompleteWarningDetailsInputVO>(MemberList.None);
CreateMap<GetPageReturnWarningDetailsInput, GetPageReturnWarningDetailsInputVO>(MemberList.None);
CreateMap<GetPageTransportWarningDetailsInput, GetPageTransportWarningDetailsInputVO>(MemberList.None);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -67,7 +67,7 @@ public class TrackOrderService : ApplicationService
[HttpGet("GetOrderTypeDict")]
public async Task<Dictionary<string, string>> GetOrderTypeDict()
{
return await _orderRepository.GetTrackOrderTypeDict();
return await _orderRepository.GetTrackOrderTypeDictAsync();
}
/// <summary>

View File

@ -57,7 +57,7 @@ public class TrackPushService : ApplicationService, ISingletonDependency
{
var orderTypes = await _trackPushConfigRepository.GetConfigTags(inputVo);
if (orderTypes.Count == 0) return new List<TrackPushConfigTagDto>();
var trackOrderTypes = await _orderRepository.GetTrackOrderTypeDict();
var trackOrderTypes = await _orderRepository.GetTrackOrderTypeDictAsync();
return orderTypes.Select(x => new TrackPushConfigTagDto
{

View File

@ -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
{
/// <summary>
/// 编辑完整预警规则列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditCompleteWarningRuleItem")]
public Task<UnifyResultDto> 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;
}
/// <summary>
@ -26,10 +46,70 @@ public class CompleteWarningService : ApplicationService
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetCompleteWarningRuleItem")]
public Task<UnifyResultDto<List<CompleteWarningRuleItemDto>>>
GetCompleteWarningRuleItem(GetCompleteWarningRuleItemInput input)
public async Task<UnifyResultDto<List<CompleteWarningRuleItemDto>>> GetCompleteWarningRuleItem(GetCompleteWarningRuleItemInput input)
{
return Task.FromResult(new UnifyResultDto<List<CompleteWarningRuleItemDto>>());
var result = await _warningRuleRepository.GetCompleteRuleItemsAsync(input.WarningId);
if (result.Count == 0)
return new UnifyResultDto<List<CompleteWarningRuleItemDto>>(true, new List<CompleteWarningRuleItemDto>());
// todo:缓存优化
var trackStatusIds = result
.SelectMany(x =>
{
// todo:逻辑优化
var checkStatusId = x.CheckPointTrackStatusId;
var requireStatusIds = x.GetRequireTrackStatusIdGroups();
requireStatusIds.Add(new HashSet<int>(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<List<NotifyUserDto>>(x.NotifyUsers)!
});
return new UnifyResultDto<List<CompleteWarningRuleItemDto>>(true, map.ToList());
List<RequireTrackStatusItem> 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<OrderTypeDto> BuildOrderTypes(CompleteWarningRuleItemEntity entity)
{
return entity.GetRuleOrderTypes()
.Select(x => new OrderTypeDto
{
OrderType = x,
OrderTypeName = orderTypeDict.GetValueOrDefault(x.ToString())
}).ToList();
}
}
/// <summary>
@ -38,9 +118,114 @@ public class CompleteWarningService : ApplicationService
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPageCompleteWarningDetails")]
public Task<UnifyPageResultDto<CompleteWarningDetailsDto>>
GetPageCompleteWarningDetails(GetPageCompleteWarningDetailsInput input)
public async Task<UnifyPageResultDto<CompleteWarningDetailsDto>> GetPageCompleteWarningDetails(GetPageCompleteWarningDetailsInput input)
{
return Task.FromResult(new UnifyPageResultDto<CompleteWarningDetailsDto>());
var vo = ObjectMapper.Map<GetPageCompleteWarningDetailsInput, GetPageCompleteWarningDetailsInputVO>(input);
var result = await _warningDetailsEsRepository.GetPageCompleteWarningDetailsAsync(vo);
if (result.List.Count == 0)
return new UnifyPageResultDto<CompleteWarningDetailsDto>(new List<CompleteWarningDetailsDto>(), 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<CompleteWarningDetailsDto>(
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<List<NotifyUserDto>>().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);
}
}
/// <summary>
/// 编辑完整预警规则列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditCompleteWarningRuleItem")]
public async Task<UnifyResultDto> 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);
}
}

View File

@ -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<TrackDeletedSignal> deletedSignals)
{
throw new NotImplementedException();
}
public Task TrackAddedHandleAsync(List<TrackAddedSignal> addedSignals)
{
throw new NotImplementedException();
}
public Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule)
{
throw new NotImplementedException();
}
#region todo: 规则项目变更
public async Task HandleEditAsync(WarningRuleEntity rule, List<CompleteWarningRuleItemBO> 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<CompleteWarningRuleItemBO>();
var deleteRuleItems = new List<CompleteWarningRuleItemBO>();
// 构建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<CompleteWarningRuleItemBO> 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<CompleteWarningRuleItemBO> bos)
{
var entities = CompleteWarningRuleItemBO.ToEntities(bos);
await _warningRuleRepository.BulkInsertCompleteRuleItemsAsync(entities);
// 更新规则主体版本号
await _warningRuleRepository.UpdateVersionAsync(rule);
}
private async Task HandleRuleItemsChangeAsync(
WarningRuleEntity rule,
List<CompleteWarningRuleItemBO> addRuleItems,
List<CompleteWarningRuleItemBO> updateRuleItems,
List<CompleteWarningRuleItemBO> 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<WarningNotifyTaskEntity> FilterAndHandleNeedNotifyTask(List<WarningNotifyTaskEntity> notifyTasks)
{
throw new NotImplementedException();
}
}

View File

@ -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
{
/// <summary>
/// 规则项目唯一id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 预警规主体id
/// </summary>
public int WarningId { get; set; }
/// <summary>
/// 订单类型集合(,分割) e.g. 1,2,3
/// </summary>
public HashSet<int> OrderTypes { get; set; }
/// <summary>
/// 检查点轨迹状态id
/// </summary>
public int CheckPointTrackStatusId { get; set; }
/// <summary>
/// 要求的轨迹状态id集合 e.g. [[1,3],[5,7]]
/// required: 集合元素(子集合)不要有交集!
/// </summary>
public List<HashSet<int>> RequireTrackStatus { get; set; }
/// <summary>
/// 通知对象用户集合
/// </summary>
public List<NotifyUserDto> NotifyUsers { get; set; } = new();
public static List<CompleteWarningRuleItemBO> 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<CompleteWarningRuleItemEntity> ToEntities(List<CompleteWarningRuleItemBO> 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<List<NotifyUserDto>>(entity.NotifyUsers)!
};
}
public static List<CompleteWarningRuleItemBO> From(List<CompleteWarningRuleItemEntity> entities)
{
return entities.Select(From).ToList();
}
}

View File

@ -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
{
/// <summary>
/// 规则项目唯一id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 预警规则主体id
/// </summary>
public int WarningId { get; set; }
/// <summary>
/// 轨迹状态
/// </summary>
public HashSet<int> TrackStatusIds { get; set; }
/// <summary>
/// 回传预警时间
/// </summary>
public float ReturnTimeSpan { get; set; } //时效(单位小时),只是用于判断状态
/// <summary>
/// 通知用户对象集合
/// </summary>
public List<NotifyUserDto> NotifyUsers { get; set; }
public static List<ReturnWarningRuleItemBO> 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<ReturnWarningRuleItemBO> From(List<ReturnWarningRuleItemEntity> 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<List<NotifyUserDto>>(entity.NotifyUsers)!
};
}
public ReturnWarningRuleItemEntity ToEntity()
{
return new ReturnWarningRuleItemEntity(
Id,
WarningId,
string.Join(',', TrackStatusIds),
ReturnTimeSpan,
TextJsonHelper.Serialize(NotifyUsers)!
);
}
public static List<ReturnWarningRuleItemEntity> ToEntities(List<ReturnWarningRuleItemBO> bos)
{
return bos.Select(x => x.ToEntity()).ToList();
}
}

View File

@ -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
{
/// <summary>
/// 场景唯一id (传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 预警规则主体id
/// </summary>
public int WarningId { get; set; }
/// <summary>
/// 是否中转(单一)
/// </summary>
public bool? IsTransit { get; set; }
/// <summary>
/// 货物类型(多个,分割)
/// </summary>
public string? CargoType { get; set; }
/// <summary>
/// 起运港口(多个,分割)
/// </summary>
public string? LeavePort { get; set; }
/// <summary>
/// 产品编码(多个,分割)
/// </summary>
public string? ProductCode { get; set; }
/// <summary>
/// 月份(多个/分割)
/// </summary>
public string? Months { get; set; }
/// <summary>
/// 区域Id(单一)
/// </summary>
public int? AreaId { get; set; }
public bool CanHitScene(OrderEntity order, List<RuleAreaInfoEntity>? 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<int>()
: 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
};
}
}

View File

@ -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;
/// <summary>
/// 处理运输时效规则项目的业务模型
/// 可以通过入参/持久化模型转化
/// </summary>
public sealed class TransportWarningSceneRuleItemBO
{
/// <summary>
/// 规则项目id(传0视为新增)
/// </summary>
public int Id { get; set; }
/// <summary>
/// 预警规主体id
/// </summary>
public int WarningId { get; set; }
/// <summary>
/// 运输预警场景id
/// </summary>
public int SceneId { get; set; }
/// <summary>
/// 起始轨迹状态Id
/// </summary>
public int StartTrackStatusId { get; set; }
/// <summary>
/// 截止轨迹状态Id
/// </summary>
public int EndTrackStatusId { get; set; }
/// <summary>
/// 时效 (单位h)
/// </summary>
public float TransportTimeSpan { get; set; }
/// <summary>
/// 起始轨迹生成预警时间 (单位h)
/// </summary>
public float StartTrackWarningTimeSpan { get; set; }
/// <summary>
/// 通知对象用户集合
/// </summary>
public List<NotifyUserDto> NotifyUsers { get; set; }
public static List<TransportWarningSceneRuleItemBO> 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<List<NotifyUserDto>>(entity.NotifyUsers)!
};
}
public static List<TransportWarningSceneRuleItemBO> From(List<TransportWarningSceneRuleItemEntity> 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<TransportWarningSceneRuleItemEntity> ToEntities(List<TransportWarningSceneRuleItemBO> bos)
{
return bos.Select(x=>x.ToEntity()).ToList();
}
public bool CanHitRule(int trackStatusId, HashSet<int> trackStatusIds)
{
return trackStatusId == StartTrackStatusId //命中起始轨迹状态
&& !trackStatusIds.Contains(EndTrackStatusId); //缺失截止轨迹状态
}
// 重新命中,用于规则扫描
public bool CanReHit(HashSet<int> trackStatusIds)
{
return trackStatusIds.Contains(StartTrackStatusId) //存在起始
&& !trackStatusIds.Contains(EndTrackStatusId); //不存在截止
}
}

View File

@ -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<IWarningSignal> updateOrDeleteSignals)
{
throw new NotImplementedException();
}
public Task<bool> 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<ReturnWarningRuleItemBO> 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<ReturnWarningRuleItemBO>();
var deleteRuleItems = new List<ReturnWarningRuleItemBO>();
// 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<ReturnWarningRuleItemBO> bos)
{
var entities = ReturnWarningRuleItemBO.ToEntities(bos);
await _warningRuleRepository.BulkInsertReturnRuleItemsAsync(entities);
// 更新规则主体版本号
await _warningRuleRepository.UpdateVersionAsync(rule);
}
private async Task OnlyDeleteHandleAsync(WarningRuleEntity rule, List<ReturnWarningRuleItemBO> 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<ReturnWarningRuleItemBO> addRuleItems,
List<ReturnWarningRuleItemBO> updateRuleItems,
List<ReturnWarningRuleItemBO> 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<ReturnWarningRuleItemEntity> DiffFilterReturnWarningRuleItems(WarningRuleEntity rule, List<ReturnWarningRuleItemEntity> postRuleItems)
{
throw new NotImplementedException();
}
public List<WarningNotifyTaskEntity> FilterAndHandleNeedNotifyTask(List<WarningNotifyTaskEntity> notifyTasks)
{
throw new NotImplementedException();
}
}

View File

@ -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<TrackDeletedSignal> deletedSignals)
{
throw new NotImplementedException();
}
public Task TrackAddedOrUpdatedHandleAsync(List<IWarningSignal> 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<TransportWarningSceneRuleItemBO> 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<TransportWarningSceneRuleItemBO>();
var deleteRuleItems = new List<TransportWarningSceneRuleItemBO>();
// 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<TransportWarningSceneRuleItemBO> bos)
{
var entities = TransportWarningSceneRuleItemBO.ToEntities(bos);
await _warningRuleRepository.BulkInsertTransportSceneRuleItemsAsync(entities);
// 更新规则主体版本号
await _warningRuleRepository.UpdateVersionAsync(rule);
}
private async Task OnlyDeleteHandleAsync(WarningRuleEntity rule, TransportWarningSceneEntity scene, List<TransportWarningSceneRuleItemBO> 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<TransportWarningSceneRuleItemBO> addRuleItems,
List<TransportWarningSceneRuleItemBO> updateRuleItems,
List<TransportWarningSceneRuleItemBO> 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<int>(2)
{
TransportWarningStatus.即将超时.GetHashCode(),
TransportWarningStatus.已超时.GetHashCode()
}
);
// 构建处理快
var handleBlocks = new List<HandleBlock>(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<string>());
await _warningDetailsEsRepository.BulkCloseTransportWarningDetailsAsync(closeDetailIds);
// 关闭相关的预警生成任务(未关闭的)
var closeGenerateTaskIds = typeIdsDict.GetValueOrDefault(HandleType.GenerateTask, new HashSet<string>());
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<string>());
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<int> 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<WarningNotifyTaskEntity> FilterAndHandleNeedNotifyTask(List<WarningNotifyTaskEntity> notifyTasks)
{
throw new NotImplementedException();
}
}

View File

@ -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<TrackDeletedSignal> deletedSignals);
// 处理轨迹 新增 todo:未实现,用于处理信号,需要支持批量处理
Task TrackAddedHandleAsync(List<TrackAddedSignal> addedSignals);
// 完整预警主体禁用 todo:未实现
Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule);
// 处理完整预警规则项变更
Task HandleEditAsync(WarningRuleEntity rule, List<CompleteWarningRuleItemBO> postRuleItems);
// 预警通知任务可行性过滤 todo:未实现
List<WarningNotifyTaskEntity> FilterAndHandleNeedNotifyTask(List<WarningNotifyTaskEntity> notifyTasks);
}

View File

@ -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<IWarningSignal> updateOrDeleteSignals);
// 收到轨迹推送记录(接口通回调)(人工介入/重试 阶段的回传) todo:未实现
Task<bool> ReceiveTrackPushRecordHandleAsync(TrackPushRecordIndex record);
// 回传预警主体禁用 todo:未实现
Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule);
// 处理推送映射配置变更 todo:未实现
Task PushConfigChangedHandleAsync(TrackPushConfigEntity pushConfig, TrackPushContentConfigEntity pushContentConfig);
// 处理编辑回传预警规则项
Task HandleEditAsync(WarningRuleEntity rule, List<ReturnWarningRuleItemBO> postRuleItems);
// 预警通知任务可行性过滤 todo:未实现
List<WarningNotifyTaskEntity> FilterAndHandleNeedNotifyTask(List<WarningNotifyTaskEntity> notifyTasks);
}

View File

@ -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;
/// <summary>
/// todo:提供业务模型的转化方法
/// </summary>
public interface ITransportWarningHandler : ITransientDependency
{
// 处理轨迹 删除 todo:用于处理信号,需要支持批量处理
Task TrackDeletedHandleAsync(List<TrackDeletedSignal> deletedSignals);
// 处理轨迹 新增/修改 todo:用于处理信号,需要支持批量处理
Task TrackAddedOrUpdatedHandleAsync(List<IWarningSignal> addOrDeleteSignals);
// 运输预警主体禁用 todo:未实现
Task WarningRuleToDisabledHandleAsync(WarningRuleEntity warningRule);
// 运输预警场景变更
Task HandleSceneChangedAsync(WarningRuleEntity rule, TransportWarningSceneBO oldScene, TransportWarningSceneBO postScene);
// 处理配置项列表保存
Task HandleEditAsync(WarningRuleEntity rule, TransportWarningSceneEntity scene, List<TransportWarningSceneRuleItemBO> bos);
// 预警通知可行性筛选 todo:未实现
List<WarningNotifyTaskEntity> FilterAndHandleNeedNotifyTask(List<WarningNotifyTaskEntity> notifyTasks);
}

View File

@ -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
{
/// <summary>
/// 编辑回传预警规则列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditReturnWarningRuleItem")]
public Task<UnifyResultDto> EditReturnWarningRuleItem(EditReturnWarningRuleItemInput input)
{
return Task.FromResult(new UnifyResultDto());
}
private readonly IReturnWarningHandler _returnWarningHandler;
private readonly IWarningRuleRepository _warningRuleRepository;
private readonly IWarningDetailsEsRepository _warningDetailsEsRepository;
private readonly ITrackStatusRepository _trackStatusRepository;
/// <summary>
/// 分页获取回传预警明细
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPageReturnWarningDetails")]
public Task<UnifyPageResultDto<ReturnWarningDetailsDto>> GetPageReturnWarningDetails(GetPageReturnWarningDetailsInput input)
public ReturnWarningService(IWarningRuleRepository warningRuleRepository, IWarningDetailsEsRepository warningDetailsEsRepository, IReturnWarningHandler returnWarningHandler, ITrackStatusRepository trackStatusRepository)
{
return Task.FromResult(new UnifyPageResultDto<ReturnWarningDetailsDto>());
}
/// <summary>
/// 获取回传报文日志
/// </summary>
[HttpPost("GetReturnMessageRecord")]
public Task<UnifyResultDto<List<ReturnMessageRecordDto>>> GetReturnMessageRecord(GetReturnMessageRecordInput input)
{
return Task.FromResult(new UnifyResultDto<List<ReturnMessageRecordDto>>());
_warningRuleRepository = warningRuleRepository;
_warningDetailsEsRepository = warningDetailsEsRepository;
_returnWarningHandler = returnWarningHandler;
_trackStatusRepository = trackStatusRepository;
}
/// <summary>
@ -46,9 +37,163 @@ public class ReturnWarningService : ApplicationService
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetReturnWarningRuleItem")]
public Task<UnifyResultDto<List<ReturnWarningRuleItemDto>>>
GetReturnWarningRuleItem(GetReturnWarningRuleItemInput input)
public async Task<UnifyResultDto<List<ReturnWarningRuleItemDto>>> GetReturnWarningRuleItem(GetReturnWarningRuleItemInput input)
{
return Task.FromResult(new UnifyResultDto<List<ReturnWarningRuleItemDto>>());
var result = await _warningRuleRepository.GetReturnRuleItemsAsync(input.WarningId);
if (result.Count == 0)
return new UnifyResultDto<List<ReturnWarningRuleItemDto>>(true, new List<ReturnWarningRuleItemDto>());
// 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<List<NotifyUserDto>>()
});
return new UnifyResultDto<List<ReturnWarningRuleItemDto>>(true, map.ToList());
// todo:拆解优化
List<TrackStatusDto> BuildTrackStatus(string statusIds)
{
return statusIds.Split(',')
.Select(x =>
{
var id = int.Parse(x);
return new TrackStatusDto
{
TrackStatus = trackStatusDict.GetValueOrDefault(id),
TrackStatusId = id
};
}).ToList();
}
}
/// <summary>
/// 分页获取回传预警明细
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPageReturnWarningDetails")]
public async Task<UnifyPageResultDto<ReturnWarningDetailsDto>> GetPageReturnWarningDetails(GetPageReturnWarningDetailsInput input)
{
var vo = ObjectMapper.Map<GetPageReturnWarningDetailsInput, GetPageReturnWarningDetailsInputVO>(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<ReturnWarningDetailsDto>(
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<List<NotifyUserDto>>().Select(x => x.UserName));
}
}
/// <summary>
/// 获取回传报文日志
/// </summary>
[HttpPost("GetReturnMessageRecord")]
public async Task<UnifyResultDto<List<ReturnMessageRecordDto>>> 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<List<ReturnMessageRecordDto>>(true, map.ToList());
}
/// <summary>
/// 编辑回传预警规则列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditReturnWarningRuleItem")]
public async Task<UnifyResultDto> 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);
}
}

View File

@ -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;
/// <summary>
/// 运输时效预警服务
@ -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;
/// <summary>
/// 编辑预警规则项目(全量)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditTransportWarningSceneRuleItem")]
public Task<UnifyResultDto>
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;
}
/// <summary>
/// 获取预警规则场景
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetTransportWarningScene")]
public async Task<UnifyResultDto<List<TransportWarningSceneDto>>> GetTransportWarningScene(GetTransportWarningSceneInput input)
{
var entities = await _warningRuleRepository.GetTransportSceneAsync(input.WarningId);
/// <summary>
/// 分页获取运输时效预警明细
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPageTransportWarningDetails")]
public Task<UnifyPageResultDto<TransportWarningDetailsDto>>
GetPageTransportWarningDetails(GetPageTransportWarningDetailsInput input)
{
return Task.FromResult(new UnifyPageResultDto<TransportWarningDetailsDto>());
}
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
});
/// <summary>
/// 获取预警规则场景
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetTransportWarningScene")]
public Task<UnifyResultDto<List<TransportWarningSceneDto>>>
GetTransportWarningScene(GetTransportWarningSceneInput input)
{
return Task.FromResult(new UnifyResultDto<List<TransportWarningSceneDto>>());
}
return new UnifyResultDto<List<TransportWarningSceneDto>>(true, map.ToList());
/// <summary>
/// 获取运输时效场景规则项目
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetTransportWarningSceneRuleItem")]
public Task<UnifyResultDto<List<TransportWarningSceneRuleItemDto>>>
GetTransportWarningSceneRuleItem(GetTransportWarningSceneRuleItemInput input)
{
return Task.FromResult(new UnifyResultDto<List<TransportWarningSceneRuleItemDto>>());
}
// 构建场景摘要
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}");
/// <summary>
/// 新增/更新 运输时效场景
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("UpsertTransportWarningScene")]
public Task<UnifyResultDto<IdBaseDto>>
UpsertTransportWarningScene(UpsertTransportWarningSceneInput input)
{
return Task.FromResult(new UnifyResultDto<IdBaseDto>());
}
return sb.ToString();
}
}
/// <summary>
/// 获取运输时效场景规则项目
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetTransportWarningSceneRuleItem")]
public async Task<UnifyResultDto<List<TransportWarningSceneRuleItemDto>>> GetTransportWarningSceneRuleItem(GetTransportWarningSceneRuleItemInput input)
{
var entities = await _warningRuleRepository.GetTransportSceneRuleItemsAsync(input.WarningId, input.SceneId);
// todo:缓存优化
var trackStatusIds = entities.SelectMany(x => new List<int>(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<List<NotifyUserDto>>()
});
return new UnifyResultDto<List<TransportWarningSceneRuleItemDto>>(true, map.ToList());
}
/// <summary>
/// 分页获取运输时效预警明细
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPageTransportWarningDetails")]
public async Task<UnifyPageResultDto<TransportWarningDetailsDto>> GetPageTransportWarningDetails(GetPageTransportWarningDetailsInput input)
{
var vo = ObjectMapper.Map<GetPageTransportWarningDetailsInput, GetPageTransportWarningDetailsInputVO>(input);
var result = await _warningDetailsEsRepository.GetPageTransportWarningDetailsAsync(vo);
if (result.List.Count == 0)
{
return new UnifyPageResultDto<TransportWarningDetailsDto>(new List<TransportWarningDetailsDto>(), 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<TransportWarningDetailsDto>(
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<List<NotifyUserDto>>().Select(x => x.UserName));
}
// 格式化累计运输时间为文本形式
string FormatCumulativeTimeSpan(long cumulativeTimeSpan)
{
var timeSpan = TimeSpan.FromMilliseconds(cumulativeTimeSpan);
return $"{timeSpan.Days:00}天{timeSpan.Hours:00}小时{timeSpan.Minutes:00}分钟";
}
}
/// <summary>
/// 新增/更新 运输时效场景
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("UpsertTransportWarningScene")]
public async Task<UnifyResultDto<IdBaseDto>> 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<IdBaseDto>(true, new IdBaseDto
{
Id = id
});
}
/// <summary>
/// 编辑预警规则项目(全量)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditTransportWarningSceneRuleItem")]
public async Task<UnifyResultDto> 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);
}
}

View File

@ -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;
}
/// <summary>
/// 新增/修改预警规则主体
/// </summary>
@ -17,18 +30,24 @@ public class WarningService : ApplicationService
[HttpPost("UpsertWarningRule")]
public async Task<UnifyResultDto<IdBaseDto>> 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<IdBaseDto>(true, new IdBaseDto
{
Id = input.Id
Id = id
});
}
@ -38,9 +57,40 @@ public class WarningService : ApplicationService
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetWarningRule")]
public Task<UnifyResultDto<List<WarningRuleDto>>> GetWarningRule(GetWarningRuleInput input)
public async Task<UnifyResultDto<List<WarningRuleDto>>> 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<List<WarningRuleDto>>(true, new List<WarningRuleDto>());
// 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<List<WarningRuleDto>>(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());
}
}

View File

@ -10,7 +10,7 @@ public interface IOrderRepository : IBasicRepository<OrderEntity>
/// key:OrderType value:TypeName
/// </summary>
/// <returns></returns>
Task<Dictionary<string, string>> GetTrackOrderTypeDict();
Task<Dictionary<string, string>> GetTrackOrderTypeDictAsync();
/// <summary>
/// 获取分页的轨迹订单

View File

@ -8,8 +8,7 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
{
Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, string trackCode, bool forUpsert = false);
// todo:s07 获取这些订单的最新一条轨迹
// Task<List<TrackDetailsIndex>> GetLatestListAsync(HashSet<int> eventOrderIds);
Task<List<TrackDetailsIndex>> GetLatestListAsync(HashSet<int> eventOrderIds);
Task<List<TrackDetailsIndex>> GetLatestListAsync(int[] eventOrderIds, List<string> trackCodes);

View File

@ -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; } // 预警处理时间
}

View File

@ -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<int> GetRuleOrderTypes()
{
return OrderTypes.Split(',').Select(int.Parse).ToHashSet();
}
public List<HashSet<int>> 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<int> trackStatusIds)
{
if (trackStatusIds.Count == 0) return true;
//组之间是并且关系,组内为或的关系
var groups = GetRequireTrackStatusIdGroups();
// 当没有某个组没有交集产生,则认定为轨迹缺失
foreach (var g in groups)
{
if (!g.Intersect(trackStatusIds).Any())
return true;
}
return false;
}
}

View File

@ -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<UnifyPageResultDto<TransportWarningDetailsIndex>> GetPageTransportWarningDetailsAsync(GetPageTransportWarningDetailsInputVO input);
// 获取运输预警明细(预警规则id+状态)
Task<List<TransportWarningDetailsIndex>> GetTransportWarningDetailsAsync(HashSet<int> ruleItemIds, HashSet<int> status);
// 更新运输预警明细
Task UpdateTransportWarningDetailsAsync(TransportWarningDetailsIndex detail);
// 批量更新运输预警明细
Task BulkUpdateTransportWarningDetailsAsync(List<TransportWarningDetailsIndex> details, int maxRetries = 3);
// 批量关闭运输预警明细
Task BulkCloseTransportWarningDetailsAsync(HashSet<string> detailIds, int maxRetries = 3);
// 批量关闭运输预警明细
Task BulkCloseTransportWarningDetailsAsync(HashSet<int> ruleItemIds, int maxRetries = 3);
// 新增运输预警明细
Task InsertTransportWarningDetailsAsync(TransportWarningDetailsIndex detail);
// 批量新增运输预警明细
Task BulkInsertTransportWarningDetailsAsync(List<TransportWarningDetailsIndex> details, int maxRetries = 3);
#endregion
#region 回传预警明细
// 分页获取回传预警明细
Task<UnifyPageResultDto<ReturnWarningDetailsIndex>> GetPageReturnWarningDetailsAsync(GetPageReturnWarningDetailsInputVO input);
// 获取回传日志列表
Task<List<ReturnMessageRecordIndex>> GetReturnMessageRecordListByIdAsync(string esId);
// 更新回传预警明细
Task UpdateReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail);
// 批量更新回传预警明细
Task BulkUpdateReturnWarningDetailsAsync(List<ReturnWarningDetailsIndex> details, int maxRetries = 3);
// 新增回传预警明细
Task InsertReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail);
// 批量新增回传预警明细
Task BulkInsertReturnWarningDetailsAsync(List<ReturnWarningDetailsIndex> details, int maxRetries = 3);
// 新增回传日志
Task InsertReturnMessageRecordAsync(ReturnMessageRecordIndex detail);
// 批量新增回传日志
Task BulkInsertReturnMessageRecordAsync(List<ReturnMessageRecordIndex> details, int maxRetries = 3);
#endregion
#region 完整预警明细
// 分页获取完整预警明细
Task<UnifyPageResultDto<CompleteWarningDetailsIndex>> GetPageCompleteWarningDetailsAsync(GetPageCompleteWarningDetailsInputVO input);
// 更新完整预警明细
Task UpdateCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail);
// 批量完整回传预警明细
Task BulkUpdateCompleteWarningDetailsAsync(List<CompleteWarningDetailsIndex> details, int maxRetries = 3);
// 新增完整预警明细
Task InsertCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail);
// 批量新增完整预警明细
Task BulkInsertCompleteWarningDetailsAsync(List<CompleteWarningDetailsIndex> details, int maxRetries = 3);
#endregion
Task CreateAliasAsync();
}

View File

@ -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;
/// <summary>
/// 预警规则仓储
/// todo:需要使用vo
/// </summary>
public interface IWarningRuleRepository : IBasicRepository<WarningRuleEntity>
{
#region 规则主体
// 检查名称是否重复
Task<bool> CheckNameDuplicateAsync(int id,int subsystemId, int customId, string name);
// 新增/更新预警规则主体,并返回id
Task<int> UpsertReturnIdAsync(WarningRuleEntity entity);
// 更新版本号
Task<string> UpdateVersionAsync(WarningRuleEntity entity);
// 模糊查询预警规则主体
Task<List<WarningRuleEntity>> GetWarningRuleListAsync(int? subsystemId, string? keyword, bool? isEnabled, int? warningType);
// 获取启用的预警规则主体
Task<WarningRuleEntity?> GetWarningRuleForEnabledAsync(int subSystemId, int customId, WarningRuleType warningType);
// 获取预警规则主体根据id
Task<WarningRuleEntity?> GetWarningRuleByIdAsync(int id, WarningRuleType? warningType = null);
#endregion
#region 运输时效预警规则
// 获取运输预警场景列表
Task<List<TransportWarningSceneEntity>> GetTransportSceneAsync(int warningId);
// 获取运输预警场景列表
Task<TransportWarningSceneEntity?> GetTransportSceneAsync(int warningId, int sceneId);
// 全量获取的运输时效场景规则项目
Task<List<TransportWarningSceneRuleItemEntity>> GetTransportSceneRuleItemsAsync(int warningId, int sceneId);
// 新增/更新 运输预警场景
Task<int> UpsertTransportSceneReturnIdAsync(TransportWarningSceneEntity entity);
// 批量更新运输时效场景规则项目
Task<int> BulkUpdateTransportSceneRuleItemsAsync(List<TransportWarningSceneRuleItemEntity> entities);
// 批量新增运输时效场景规则项目
Task<int> BulkInsertTransportSceneRuleItemsAsync(List<TransportWarningSceneRuleItemEntity> entities);
// 删除运输预警场景规则项目
Task<int> DeleteTransportSceneRuleItemsAsync(HashSet<int> ruleItemIds);
#endregion
#region 回传时效预警规则
// 获取全量回传预警规则规则项目
Task<List<ReturnWarningRuleItemEntity>> GetReturnRuleItemsAsync(int warningId);
// 批量新增回传时效场景规则项目
Task<int> BulkInsertReturnRuleItemsAsync(List<ReturnWarningRuleItemEntity> entities);
// 批量更新回传预警规则规则项目
Task<int> BulkUpdateReturnRuleItemsAsync(List<ReturnWarningRuleItemEntity> entities);
// 删除回传预警规则项目
Task<int> DeleteReturnRuleItemsAsync(HashSet<int> ruleItemIds);
#endregion
#region 完整预警规则
// 获取全量预警规则规则项目
Task<List<CompleteWarningRuleItemEntity>> GetCompleteRuleItemsAsync(int warningId);
// 批量更新预警规则规则项目
Task<int> BulkUpdateCompleteRuleItemsAsync(List<CompleteWarningRuleItemEntity> entities);
// 批量新增完整时效规则项目
Task<int> BulkInsertCompleteRuleItemsAsync(List<CompleteWarningRuleItemEntity> entities);
// 删除完整预警场景规则项目
Task<int> DeleteCompleteRuleItemsAsync(HashSet<int> ruleItemIds);
#endregion
}

View File

@ -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<List<WarningNotifyTaskEntity>> ScanMayNeedExecutedTaskAsync();
// 获取预警通知任务
Task<List<WarningNotifyTaskEntity>> GetWarningNotifyTaskAsync(Expression<Func<WarningNotifyTaskEntity, bool>> expression);
// 添加一个预警通知任务
Task<bool> AddWarningNotifyTaskAsync(WarningNotifyTaskEntity entity);
// 批量添加预警通知任务
Task<int> BulkInsertWarningNotifyTaskAsync(List<WarningNotifyTaskEntity> entities);
// 关闭预警通知任务
Task<int> CloseWarningNotifyTaskAsync(Expression<Func<WarningNotifyTaskEntity, bool>> expression);
// 关闭预警通知任务
Task<bool> CloseWarningNotifyTaskAsync(WarningNotifyTaskEntity entity);
#endregion
#region 回传预警_重试推送任务
// 扫描重试推送任务
Task<List<ReturnWarningRetryPushTaskEntity>> ScanReturnWarningRetryPushTaskAsync();
// 条件获取重试推送任务
Task<List<ReturnWarningRetryPushTaskEntity>> GetReturnWarningRetryPushTaskAsync(Expression<Func<ReturnWarningRetryPushTaskEntity, bool>> expression);
// 添加回传预警_重试推送任务
Task<bool> AddReturnWarningRetryPushTaskAsync(ReturnWarningRetryPushTaskEntity entity);
// 批量添加回传预警_重试推送任务
Task<int> BulkInsertReturnWarningRetryPushTaskAsync(List<ReturnWarningRetryPushTaskEntity> entities);
// 条件关闭回传预警_重试推送任务
Task<int> CloseReturnWarningRetryPushTaskAsync(Expression<Func<ReturnWarningRetryPushTaskEntity, bool>> expression);
// 关闭回传预警_重试推送任务
Task<bool> CloseReturnWarningRetryPushTaskAsync(ReturnWarningRetryPushTaskEntity entity);
#endregion
#region 运输预警_预警明细生成任务
// 扫描预警明细生成任务
Task<List<TransportWarningDetailsGenerateTaskEntity>> ScanTransportWarningDetailsGenerateTaskAsync();
// 条件获取运输预警明细生成任务
Task<List<TransportWarningDetailsGenerateTaskEntity>> GetTransportWarningDetailsGenerateTaskAsync(Expression<Func<TransportWarningDetailsGenerateTaskEntity, bool>> expression);
// 添加运输预警明细生成任务
Task<bool> AddTransportWarningDetailsGenerateTaskAsync(TransportWarningDetailsGenerateTaskEntity entity);
// 批量添加运输预警明细生成任务
Task<int> BulkInsertTransportWarningDetailsGenerateTaskAsync(List<TransportWarningDetailsGenerateTaskEntity> entities);
// 批量更新运输预警明细生成任务
Task<int> BulkUpdateTransportWarningDetailsGenerateTaskAsync(List<TransportWarningDetailsGenerateTaskEntity> entities);
// 条件关闭运输预警明细生成任务
Task<int> CloseTransportWarningDetailsGenerateTaskAsync(Expression<Func<TransportWarningDetailsGenerateTaskEntity, bool>> expression);
// 关闭运输预警明细生成任务
Task<bool> CloseTransportWarningDetailsGenerateTaskAsync(TransportWarningDetailsGenerateTaskEntity entity);
#endregion
}

View File

@ -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; } //报文创建时间
}

View File

@ -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);
}
}

View File

@ -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; } // 已关闭的任务不会在执行
}

View File

@ -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<int> GetRuleStatusIds()
{
return TrackStatusIds.Split(',').Select(int.Parse).ToHashSet();
}
public bool CanHitRule(int trackStatusId)
{
return GetRuleStatusIds().Contains(trackStatusId);
}
}

View File

@ -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,
}

View File

@ -0,0 +1,13 @@
namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
/// <summary>
/// 轨迹新增信号
/// </summary>
public sealed class TrackAddedSignal : IWarningSignal
{
public WarningSignalType Type { get; set; } = WarningSignalType.轨迹新增;
public int OrderId { get; set; }
public string EsId { get; set; } //新增轨迹的esId
}

View File

@ -0,0 +1,15 @@
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
/// <summary>
/// 轨迹删除信号
/// </summary>
public class TrackDeletedSignal : IWarningSignal
{
public WarningSignalType Type { get; set; } = WarningSignalType.轨迹删除;
public int OrderId { get; set; }
public TrackDetailsIndex DeletedTrack { get; set; } //已删除的轨迹
}

View File

@ -0,0 +1,16 @@
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
namespace SJZY.Track.Domain.Aggregates.WarningAggregate.Signals;
/// <summary>
/// 轨迹更新信号
/// </summary>
public class TrackUpdatedSignal:IWarningSignal
{
public WarningSignalType Type { get; set; } = WarningSignalType.轨迹更新;
public int OrderId { get; set; }
public TrackDetailsIndex BeforeChangeTrack { get; set; } //更改前的轨迹明细
}

View File

@ -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; } //是否关闭,执行完成被关闭/手动关闭
}

View File

@ -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<int> 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));
}
}

View File

@ -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;
}
}

View File

@ -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<int> trackStatusIds)
{
return trackStatusId == StartTrackStatusId //命中起始轨迹状态
&& !trackStatusIds.Contains(EndTrackStatusId); //缺失截止轨迹状态
}
// 重新命中,用于规则扫描
public bool CanReHit(HashSet<int> trackStatusIds)
{
return trackStatusIds.Contains(StartTrackStatusId) //存在起始
&& !trackStatusIds.Contains(EndTrackStatusId); //不存在截止
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,60 @@
namespace SJZY.Track.Domain.Dtos.Warning;
public class GetPageCompleteWarningDetailsInputVO : PageInfoInput
{
/// <summary>
/// 子系统id
/// </summary>
public int? SubSystemId { get; set; }
/// <summary>
/// 订单号,多个订单号(,分割)
/// </summary>
public string? OrderNos { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int? OrderType { get; set; }
/// <summary>
/// 状态
/// 1:待处理,2:已处理,3:已关闭
/// </summary>
public int? Status { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int? CustomId { get; set; }
/// <summary>
/// 缺失轨迹状态id
/// </summary>
public int? MissingTrackStatusId { get; set; }
/// <summary>
/// 通知对象id
/// </summary>
public int? NotifyUserId { get; set; }
/// <summary>
/// 预警创建时间开始
/// </summary>
public DateTime? WarningCreateTimeStart { get; set; }
/// <summary>
/// 预警创建时间截止
/// </summary>
public DateTime? WarningCreateTimeEnd { get; set; }
/// <summary>
/// 预警处理时间开始
/// </summary>
public DateTime? WarningHandleTimeStart { get; set; }
/// <summary>
/// 预警处理时间截止
/// </summary>
public DateTime? WarningHandleTimeEnd { get; set; }
}

View File

@ -0,0 +1,93 @@
namespace SJZY.Track.Domain.Dtos.Warning;
/// <summary>
/// 分页获取回传预警明细输入
/// </summary>
public class GetPageReturnWarningDetailsInputVO : PageInfoInput
{
/// <summary>
/// 子系统id
/// </summary>
public int? SubSystemId { get; set; }
/// <summary>
/// 订单号,多个订单号(,分割)
/// </summary>
public string? OrderNos { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int? OrderType { get; set; }
/// <summary>
/// 状态
/// 1:人工介入 2:重试中 3:推送完成 4:已关闭
/// </summary>
public int? Status { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int? CustomId { get; set; }
/// <summary>
/// 轨迹状态id
/// </summary>
public int? TrackStatusId { get; set; }
/// <summary>
/// 轨迹内容id
/// </summary>
public int? TrackContentId { get; set; }
/// <summary>
/// 是否有Kpi考核 (传null为查全部)
/// </summary>
public bool? IsKpi { get; set; }
/// <summary>
/// 通知对象用户id
/// </summary>
public int? NotifyUserId { get; set; }
/// <summary>
/// 轨迹发生时间开始
/// </summary>
public DateTime? TrackTimeStart { get; set; }
/// <summary>
/// 轨迹发生时间截止
/// </summary>
public DateTime? TrackTimeEnd { get; set; }
/// <summary>
/// 轨迹创建时间开始
/// </summary>
public DateTime? TrackCreateTimeStart { get; set; }
/// <summary>
/// 轨迹创建时间截止
/// </summary>
public DateTime? TrackCreateTimeEnd { get; set; }
/// <summary>
/// 轨迹回传时间开始
/// </summary>
public DateTime? TrackReturnTimeStart { get; set; }
/// <summary>
/// 轨迹回传时间截止
/// </summary>
public DateTime? TrackReturnTimeEnd { get; set; }
/// <summary>
/// 预警创建时间开始
/// </summary>
public DateTime? WarningCreateTimeStart { get; set; }
/// <summary>
/// 预警创建时间截止
/// </summary>
public DateTime? WarningCreateTimeEnd { get; set; }
}

View File

@ -0,0 +1,52 @@
namespace SJZY.Track.Domain.Dtos.Warning;
/// <summary>
/// 分页获取运输预警明细
/// </summary>
public class GetPageTransportWarningDetailsInputVO : PageInfoInput
{
/// <summary>
/// 子系统id
/// </summary>
public int? SubSystemId { get; set; }
/// <summary>
/// 订单号,多个订单号(,分割)
/// </summary>
public string? OrderNos { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public int? OrderType { get; set; }
/// <summary>
/// 状态
/// </summary>
public int? Status { get; set; }
/// <summary>
/// 客户Id
/// </summary>
public int? CustomId { get; set; }
/// <summary>
/// 预警名称
/// </summary>
public string? WarningName { get; set; }
/// <summary>
/// 通知对象用户Id
/// </summary>
public int? NotifyUserId { get; set; }
/// <summary>
/// 创建时间开始
/// </summary>
public DateTime? CreateTimeStart { get; set; }
/// <summary>
/// 创建时间截止
/// </summary>
public DateTime? CreateTimeEnd { get; set; }
}

View File

@ -0,0 +1,8 @@
namespace SJZY.Track.Domain.Enums;
public enum CompleteWarningStatus
{
待处理 = 1,
已处理 = 2,
已关闭 = 3
}

View File

@ -0,0 +1,9 @@
namespace SJZY.Track.Domain.Enums;
public enum ReturnWarningStatus
{
人工介入 = 1,
重试中 = 2,
推送完成 = 3,
已关闭 = 4
}

View File

@ -0,0 +1,10 @@
namespace SJZY.Track.Domain.Enums;
public enum TransportWarningStatus
{
即将超时 = 1,
已超时 = 2,
已完成 = 3,
超时完成 = 4,
已关闭 = 5,
}

View File

@ -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<TInput, Func<QueryContainerDescriptor<TIndex>, QueryContainer>> CreateListWrapper<TIndex, TInput>(TInput input)
where TIndex : IdBaseIndex
{
return new ListWrapper<TInput, Func<QueryContainerDescriptor<TIndex>, QueryContainer>>(new (), input);
}
}
public class ListWrapper<TInput, TItem> : List<TItem>
{
public List<TItem> List { get; set; }
public TInput Input { get; set; }
public ListWrapper(List<TItem> list, TInput input)
{
List = list;
Input = input;
}
public void AddIf(Predicate<TInput> predicate,TItem item)
{
if(predicate(Input))
List.Add(item);
}
}
public static class CollectionExtensions
{
private static readonly ConcurrentDictionary<Type, object?> DefaultValueCache = new();
public static void AddNotEmpty<TInput, TItem>(this ICollection<TItem> list, TInput input, TItem item)
{
if (input is null) return;
var t = typeof(TInput);
if (t == typeof(string))
{
if (!string.IsNullOrWhiteSpace(input as string))
list.Add(item);
return;
}
// 如果是Nullable类型,则获取其UnderlyingType
if (t.Name.StartsWith("Nullable"))
{
t = Nullable.GetUnderlyingType(t)!;
// 判断是否为数值类型
if (t.IsNumericType())
{
// 动态转换为数值比较
dynamic val = Convert.ChangeType(input, t);
dynamic defaultVal = Activator.CreateInstance(t);
// 当值为0时视为默认值
if (val != defaultVal)
{
list.Add(item);
}
}
return;
}
// 获取类型对应的默认值(带缓存)
var defaultValue = (TInput)DefaultValueCache.GetOrAdd(t, _ => default(TInput))!;
// 使用 EqualityComparer 避免装箱拆箱
if (!EqualityComparer<TInput>.Default.Equals(input, defaultValue))
{
list.Add(item);
}
}
public static void AddNotEmpty<TInput, TItem>(this ICollection<TItem> list, TInput input, Func<TInput, TItem> factory)
{
AddNotEmpty(list, input, factory(input));
}
public static void AddIf<TInput, TItem>(this ICollection<TItem> list, TInput input, Func<TInput, bool> predicate, TItem item)
{
if (predicate(input))
list.Add(item);
}
public static void AddIf<TInput, TItem>(this ICollection<TItem> list, TInput input, Func<TInput, bool> predicate, Func<TInput, TItem> factory)
{
if (predicate(input))
list.Add(factory(input));
}
private static bool IsNumericType(this Type? type)
{
if (type == null) return false;
return Type.GetTypeCode(type) switch
{
TypeCode.Byte or
TypeCode.SByte or
TypeCode.UInt16 or
TypeCode.UInt32 or
TypeCode.UInt64 or
TypeCode.Int16 or
TypeCode.Int32 or
TypeCode.Int64 or
TypeCode.Decimal or
TypeCode.Double or
TypeCode.Single => true,
_ => false
};
}
}

View File

@ -0,0 +1,34 @@
namespace SJZY.Track.Domain.Extensions;
public static class PollyHelper
{
public static async Task<TResult> RetryPollyExecAsync<TResult>(Func<Task<TResult>> func, Func<TResult, bool> successValidator, int maxRetries = 3, bool throwOtherException = true)
{
TResult result = default!;
var retryCount = 0;
try
{
while (retryCount < maxRetries)
{
result = await func();
// 如果认为成功则直返回值
if (successValidator(result))
return result;
// 超过最大重试次数,抛出异常
retryCount++;
if (retryCount >= maxRetries)
throw new InvalidOperationException($"操作失败超过最大重试次数{maxRetries}次,原因:{result}。");
}
}
catch (Exception)
{
if (throwOtherException)
throw;
}
return result;
}
}

View File

@ -1,7 +1,6 @@
using System.Globalization;
using System.Text.Json;
namespace SJZY.Track.Application.Helpers;
namespace SJZY.Track.Domain.Extensions;
/// <summary>
/// 针对 Text.Json 的一些辅助方法
@ -178,4 +177,11 @@ public static class TextJsonHelper
return false;
}
public static bool EqJsonStringField(string json1, string json2, string fieldName)
{
var aJsonElement = JsonDocument.Parse(json1);
var bJsonElement = JsonDocument.Parse(json2);
return EqByJsonElementField(aJsonElement, bJsonElement, fieldName);
}
}

View File

@ -0,0 +1,15 @@
namespace SJZY.Track.Domain.Extensions;
public static class VersionGenerate
{
/// <summary>
/// 生成版本号 guid+日期
/// </summary>
/// <returns></returns>
public static string GenVersion()
{
var guid = Guid.NewGuid().ToString("N");
var date = DateTime.Now.ToString("s");
return $"{guid}-{date}";
}
}

View File

@ -0,0 +1,7 @@
using SJZY.Track.Domain.VEntities;
namespace SJZY.Track.Domain.Queries;
public interface IVExternalSubjectQueries : IBasicQuery<VExternalSubjectEntity>
{
}

View File

@ -4,7 +4,7 @@
/// 外部主体
/// </summary>
[SugarTable("v_external_subject")]
public class VExternalSubjectEntity : IFullAuditedBasicEntitys
public class VExternalSubjectEntity : IFullAuditedBasicEntitys,IEntity
{
/// <summary>
///

View File

@ -0,0 +1,8 @@
using SJZY.Track.Domain.Queries;
using SJZY.Track.Domain.VEntities;
namespace SJZY.Track.Repository.Queries;
public class VExternalSubjectQueries : BasicQuery<VExternalSubjectEntity>, IVExternalSubjectQueries, ITransientDependency
{
}

View File

@ -62,7 +62,7 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
return dict;
}
public async Task<Dictionary<string, string>> GetTrackOrderTypeDict()
public async Task<Dictionary<string, string>> GetTrackOrderTypeDictAsync()
{
const string key = "TrackOrderType";
var orderTypes = await _memoryCache.GetOrCreateAsync(key, async (entry) =>

View File

@ -61,6 +61,44 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
return r.ToIdList();
}
public async Task<List<TrackDetailsIndex>> GetLatestListAsync(HashSet<int> eventOrderIds)
{
var r = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Index(GlobalConst.TrackDetailsIndex)
.Source()
.Query(q => q
.Bool(b => b
.Must(
mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(eventOrderIds))
)
)
)
.Size(SafelyLimit)
.Aggregations(a => a
.Terms("orders", t => t
.Field(f => f.OrderId)
.Aggregations(aa => aa
.TopHits("latest_track", th => th
.Size(1)
.Sort(so => so
.Field(f => f.ZeroTrackTime, SortOrder.Descending)
)
.Source()
)
)
)
)
);
if (!r.IsValid)
{
throw new InvalidOperationException(
$"最新轨迹查询失败,orderIds:[{eventOrderIds.JoinAsString(", ")}],原因:{r.DebugInformation}。");
}
return r.Documents.ToList();
}
public async Task<List<TrackDetailsIndex>> GetLatestListAsync(int[] orderIds, List<string> trackCodes)
{
var excludeTrackCodes = trackCodes.ToList();

View File

@ -0,0 +1,707 @@
using Nest;
using SJZY.Expand.ElasticSearch.Services;
using SJZY.Track.Domain.Aggregates.WarningAggregate;
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.Consts;
using SJZY.Track.Domain.Dtos.Warning;
using SJZY.Track.Domain.Enums;
using SJZY.Track.Domain.Extensions;
namespace SJZY.Track.Repository.Repositories;
public class WarningDetailsEsRepository : IWarningDetailsEsRepository, ITransientDependency
{
private readonly IElasticClient _client;
public WarningDetailsEsRepository(ConnectionFactory connection)
{
_client = connection.GetContext(typeof(TransportWarningDetailsIndex));
}
#region 运输时效
public async Task<UnifyPageResultDto<TransportWarningDetailsIndex>> GetPageTransportWarningDetailsAsync(GetPageTransportWarningDetailsInputVO input)
{
var musts = ListWrapperFactory.CreateListWrapper<TransportWarningDetailsIndex, GetPageTransportWarningDetailsInputVO>(input);
var orderNos = input.OrderNos?.Split(',');
// 精确匹配
musts.AddIf(x => x.CustomId > 0, c => c.Term(f => f.CustomId, input.CustomId));
musts.AddIf(_ => orderNos?.Length > 0, c => c.Terms(f => f.Field(d => d.OrderNo.Suffix("keyword")).Terms(orderNos)));
musts.AddIf(x => x.OrderType > 0, c => c.Term(f => f.OrderType, input.OrderType));
musts.AddIf(x => x.Status > 0, c => c.Term(f => f.Status, input.Status));
musts.AddIf(x => x.CustomId > 0, c => c.Term(f => f.CustomId, input.CustomId));
musts.AddIf(x => !string.IsNullOrWhiteSpace(x.WarningName), c => c.Term(f => f.WarningName, input.WarningName));
musts.AddIf(x => x.CreateTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.CreateTime).GreaterThanOrEquals(input.CreateTimeStart)));
musts.AddIf(x => x.CreateTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.CreateTime).LessThanOrEquals(input.CreateTimeEnd)));
// 模糊匹配userId
musts.AddIf(x => x.NotifyUserId.HasValue, c => c.Match(f => f.Field(d => d.NotifyUsers).Query(input.NotifyUserId.ToString())));
var resp = await _client.SearchAsync<TransportWarningDetailsIndex>(x => x
.Index(GlobalConst.TransportWarningDetailsIndex)
.Query(q => q.Bool(b => b.Must(musts)))
.From((input.PageIndex - 1) * input.PageSize)
.Size(input.PageSize));
return new UnifyPageResultDto<TransportWarningDetailsIndex>(resp.ToIdList(), input.PageIndex, input.PageSize, (int) resp.Total);
}
public async Task<List<TransportWarningDetailsIndex>> GetTransportWarningDetailsAsync(HashSet<int> ruleItemIds, HashSet<int> status)
{
var r = await _client.SearchAsync<TransportWarningDetailsIndex>(x => x
.Index(GlobalConst.TransportWarningDetailsIndex)
.Query(q => q
.Bool(b => b
.Must(
mu => mu.Terms(t => t.Field(f => f.WarningSceneRuleItemId).Terms(ruleItemIds)),
mu => mu.Terms(t => t.Field(f => f.Status).Terms(status)))
)));
return r.Documents.ToList();
}
public async Task UpdateTransportWarningDetailsAsync(TransportWarningDetailsIndex detail)
{
var r = await _client.UpdateAsync<TransportWarningDetailsIndex, object>(detail.Id,
u => u.Index(detail.IndexName)
.Doc(new
{
detail.WarningId,
detail.WarningSceneId,
detail.WarningSceneRuleItemId,
detail.Version,
detail.WarningName,
detail.WarningRuleDescription,
detail.TransportTimeSpan,
detail.StartTrackWarningTimeSpan,
//detail.NotifyModes,
detail.NotifyUsers,
detail.SubSystemId,
detail.CustomId,
detail.CustomName,
detail.OrderId,
detail.OrderNo,
detail.OrderType,
detail.StartTrackStatusId,
detail.StartTrackContentId,
detail.StartTrackTime,
detail.StartTrackTimeZone,
detail.EndTrackStatusId,
detail.EndTrackContentId,
detail.EndTrackTime,
detail.EndTrackTimeZone,
// detail.LatestTrackContentId,
// detail.LatestTrackContent,
// detail.LatestTrackTime,
// detail.LatestTrackTimeZone,
// detail.LatestTrackPlace,
detail.CumulativeTimeSpan,
detail.Status,
detail.CreateTime,
}));
}
public async Task BulkUpdateTransportWarningDetailsAsync(List<TransportWarningDetailsIndex> details, int maxRetries = 3)
{
if (details.Count == 0) return;
//构建批量更新操作描述符
var desc = new BulkDescriptor().UpdateMany(details,
(u, detail) => u.Id(detail.Id)
.Index(detail.IndexName)
.Script(s => s.Source(@"
ctx._source.WarningId = param.WarningId;
ctx._source.WarningSceneId = param.WarningSceneId;
ctx._source.WarningSceneRuleItemId = param.WarningSceneRuleItemId;
ctx._source.Version = param.Version;
ctx._source.WarningName = param.WarningName;
ctx._source.WarningRuleDescription = param.WarningRuleDescription;
ctx._source.TransportTimeSpan = param.TransportTimeSpan;
ctx._source.StartTrackWarningTimeSpa = param.StartTrackWarningTimeSpa;n
//ctx._source.NotifyModes = param.NotifyModes;
ctx._source.NotifyUsers = param.NotifyUsers;
ctx._source.SubSystemId = param.SubSystemId;
ctx._source.CustomId = param.CustomId;
ctx._source.CustomName = param.CustomName;
ctx._source.OrderId = param.OrderId;
ctx._source.OrderNo = param.OrderNo;
ctx._source.OrderType = param.OrderType;
ctx._source.StartTrackStatusId = param.StartTrackStatusId;
ctx._source.StartTrackContentId = param.StartTrackContentId;
ctx._source.StartTrackTime = param.StartTrackTime;
ctx._source.StartTrackTimeZone = param.StartTrackTimeZone;
ctx._source.EndTrackStatusId = param.EndTrackStatusId;
ctx._source.EndTrackContentId = param.EndTrackContentId;
ctx._source.EndTrackTime = param.EndTrackTime;
ctx._source.EndTrackTimeZone = param.EndTrackTimeZone;
//ctx._source.LatestTrackContentId = param.LatestTrackContentId;
//ctx._source.LatestTrackContent = param.LatestTrackContent;
//ctx._source.LatestTrackTime = param.LatestTrackTime;
//ctx._source.LatestTrackTimeZone = param.LatestTrackTimeZone;
//ctx._source.LatestTrackPlace = param.LatestTrackPlace;
ctx._source.CumulativeTimeSpan = param.CumulativeTimeSpan;
ctx._source.Status = param.Status;
ctx._source.CreateTime = param.CreateTime;
").Params(p => p
.Add("WarningId", detail.WarningId)
.Add("WarningSceneId", detail.WarningSceneId)
.Add("WarningSceneRuleItemId", detail.WarningSceneRuleItemId)
.Add("Version", detail.Version)
.Add("WarningName", detail.WarningName)
.Add("WarningRuleDescription", detail.WarningRuleDescription)
.Add("TransportTimeSpan", detail.TransportTimeSpan)
.Add("StartTrackWarningTimeSpan", detail.StartTrackWarningTimeSpan)
//.Add("NotifyModes", detail.NotifyModes)
.Add("NotifyUsers", detail.NotifyUsers)
.Add("SubSystemId", detail.SubSystemId)
.Add("CustomId", detail.CustomId)
.Add("CustomName", detail.CustomName)
.Add("OrderId", detail.OrderId)
.Add("OrderNo", detail.OrderNo)
.Add("OrderType", detail.OrderType)
.Add("StartTrackStatusId", detail.StartTrackStatusId)
.Add("StartTrackContentId", detail.StartTrackContentId)
.Add("StartTrackTime", detail.StartTrackTime)
.Add("StartTrackTimeZone", detail.StartTrackTimeZone)
.Add("EndTrackStatusId", detail.EndTrackStatusId)
.Add("EndTrackContentId", detail.EndTrackContentId)
.Add("EndTrackTime", detail.EndTrackTime)
.Add("EndTrackTimeZone", detail.EndTrackTimeZone)
// .Add("LatestTrackContentId", detail.LatestTrackContentId)
// .Add("LatestTrackContent", detail.LatestTrackContent)
// .Add("LatestTrackTime", detail.LatestTrackTime)
// .Add("LatestTrackTimeZone", detail.LatestTrackTimeZone)
// .Add("LatestTrackPlace", detail.LatestTrackPlace)
// .Add("CumulativeTimeSpan", detail.CumulativeTimeSpan)
.Add("Status", detail.Status)
.Add("CreateTime", detail.CreateTime)
)));
await PollyHelper.RetryPollyExecAsync(() => _client.BulkAsync(desc), response =>
{
if (response.IsValid) // 认为成功
return true;
if (response.ServerError.Status == 409) //版本冲突认为失败,则重试
return false;
throw new InvalidOperationException($"ES更新失败:{details.Count}条,原因:{response.DebugInformation}。");
});
}
public async Task BulkCloseTransportWarningDetailsAsync(HashSet<string> detailIds, int maxRetries = 3)
{
var status = new HashSet<int>(2)
{
TransportWarningStatus.即将超时.GetHashCode(),
TransportWarningStatus.已超时.GetHashCode()
};
var r = await _client.UpdateByQueryAsync<TransportWarningDetailsIndex>(u =>
u.Index(GlobalConst.TransportWarningDetailsIndex)
.Query(q => q
.Bool(b => b.Must(
mu => mu.Terms(t => t.Field(f => f.Status).Terms(status)),
mu => mu.Terms(t => t.Field(f => f.Id).Terms(detailIds))
)
)
)
.Script(s => s
.Source("ctx._source.status = params.status")
.Params(p => p.Add("status", (int) TransportWarningStatus.已关闭))
)
);
if (!r.IsValid)
{
throw new InvalidOperationException(
$"运输时效预警明细更新失败,detailsIds:{detailIds},原因:{r.DebugInformation}。");
}
}
public async Task BulkCloseTransportWarningDetailsAsync(HashSet<int> ruleItemIds, int maxRetries = 3)
{
var status = new HashSet<int>(2)
{
TransportWarningStatus.即将超时.GetHashCode(),
TransportWarningStatus.已超时.GetHashCode()
};
var r = await _client.UpdateByQueryAsync<TransportWarningDetailsIndex>(u =>
u.Index(GlobalConst.TransportWarningDetailsIndex)
.Query(q => q
.Bool(b => b.Must(
mu => mu.Terms(t => t.Field(f => f.Status).Terms(status)),
mu => mu.Terms(t => t.Field(f => f.WarningSceneRuleItemId).Terms(ruleItemIds))
)
)
)
.Script(s => s
.Source("ctx._source.status = params.status")
.Params(p => p.Add("status", (int) TransportWarningStatus.已关闭))
)
);
if (!r.IsValid)
{
throw new InvalidOperationException(
$"运输时效预警明细更新失败,ruleItemIds:{ruleItemIds},原因:{r.DebugInformation}。");
}
}
public async Task InsertTransportWarningDetailsAsync(TransportWarningDetailsIndex detail)
{
var indexName = $"{GlobalConst.TransportWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
detail.IndexName = indexName;
var r = await _client.IndexAsync(detail, s => s.Index(indexName));
if (!r.IsValid)
{
throw new InvalidOperationException($"运输预警明细新增失败,{detail},原因:{r.DebugInformation}。");
}
}
public async Task BulkInsertTransportWarningDetailsAsync(List<TransportWarningDetailsIndex> details, int maxRetries = 3)
{
// 按天写入es
var indexName = $"{GlobalConst.TransportWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
details.ForEach(x => x.IndexName = indexName);
var r = await _client.IndexManyAsync(details, indexName);
if (!r.IsValid)
{
throw new InvalidOperationException($"运输预警明细新增失败,原因:{r.DebugInformation}。");
}
}
#endregion
#region 回传时效
public async Task<UnifyPageResultDto<ReturnWarningDetailsIndex>> GetPageReturnWarningDetailsAsync(GetPageReturnWarningDetailsInputVO input)
{
var musts = ListWrapperFactory.CreateListWrapper<ReturnWarningDetailsIndex, GetPageReturnWarningDetailsInputVO>(input);
var orderNos = input.OrderNos?.Split(',');
// 精确匹配
musts.AddIf(x => x.SubSystemId > 0, c => c.Term(f => f.SubSystemId, input.SubSystemId));
musts.AddIf(_ => orderNos?.Length > 0, c => c.Terms(f => f.Field(d => d.OrderNo.Suffix("keyword")).Terms(orderNos)));
musts.AddIf(x => x.OrderType > 0, c => c.Term(f => f.OrderType, input.OrderType));
musts.AddIf(x => x.Status > 0, c => c.Term(f => f.Status, input.Status));
musts.AddIf(x => x.CustomId > 0, c => c.Term(f => f.CustomId, input.CustomId));
musts.AddIf(x => x.TrackStatusId > 0, c => c.Term(f => f.TrackStatusId, input.TrackStatusId));
musts.AddIf(x => x.TrackContentId > 0, c => c.Term(f => f.TrackContentId, input.TrackContentId));
musts.AddIf(x => x.IsKpi.HasValue, c => c.Term(f => f.IsExistsKpi, input.IsKpi!.Value));
musts.AddIf(x => x.TrackTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.TrackTime).GreaterThanOrEquals(input.TrackTimeStart)));
musts.AddIf(x => x.TrackTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.TrackTime).LessThanOrEquals(input.TrackTimeEnd)));
musts.AddIf(x => x.TrackCreateTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.TrackCreateTime).LessThanOrEquals(input.TrackCreateTimeStart)));
musts.AddIf(x => x.TrackCreateTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.TrackCreateTime).LessThanOrEquals(input.TrackCreateTimeEnd)));
musts.AddIf(x => x.TrackReturnTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.TrackReturnTime).LessThanOrEquals(input.TrackReturnTimeStart)));
musts.AddIf(x => x.TrackReturnTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.TrackReturnTime).LessThanOrEquals(input.TrackReturnTimeEnd)));
musts.AddIf(x => x.WarningCreateTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.CreateTime).LessThanOrEquals(input.WarningCreateTimeStart)));
musts.AddIf(x => x.WarningCreateTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.CreateTime).LessThanOrEquals(input.WarningCreateTimeEnd)));
// 模糊匹配userId(json字符串包含userId)
musts.AddIf(x => x.NotifyUserId.HasValue, c => c.Match(f => f.Field(d => d.NotifyUsers).Query(input.NotifyUserId.ToString())));
var resp = await _client.SearchAsync<ReturnWarningDetailsIndex>(x => x
.Index(GlobalConst.ReturnWarningDetailsIndex)
.Query(q => q.Bool(b => b.Must(musts)))
.From((input.PageIndex - 1) * input.PageSize)
.Size(input.PageSize));
return new UnifyPageResultDto<ReturnWarningDetailsIndex>(resp.ToIdList(), input.PageIndex, input.PageSize, (int) resp.Total);
}
public async Task<List<ReturnMessageRecordIndex>> GetReturnMessageRecordListByIdAsync(string esId)
{
var resp = await _client.SearchAsync<ReturnMessageRecordIndex>(x => x
.Index(GlobalConst.ReturnMessageRecordIndex)
.Query(q => q.Term(t => t.WarningDetailsId.Suffix("keyword"), esId))
.Size(1000)
);
return resp.ToIdList();
}
public async Task UpdateReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail)
{
var r = await _client.UpdateAsync<ReturnWarningDetailsIndex, object>(detail.Id,
u => u.Index(detail.IndexName)
.Doc(new
{
detail.ReturnWarningRuleId,
detail.WarningId,
detail.Version,
detail.ReturnTimeSpan,
//detail.NotifyModes,
detail.NotifyUsers,
detail.SubSystemId,
detail.CustomId,
detail.OrderId,
detail.OrderNo,
detail.OrderType,
detail.TrackStatusId,
detail.TrackStatus,
detail.CompareFields,
detail.Extra,
detail.TrackContentId,
detail.TrackContent,
detail.TrackCode,
detail.TrackPlace,
detail.TrackTime,
detail.TrackTimeZone,
detail.TrackCreateTime,
detail.PushTrackStatus,
detail.PushTrackCode,
detail.PushTrackContent,
detail.PushTrackEnContent,
detail.TrackReturnTime,
detail.RetryCount,
detail.Status,
detail.ActualReturnTimeSpan,
detail.SystemReturnTimeSpan,
detail.TrackCreateTimeSpan,
detail.CreateTime,
detail.UpdateTime,
}));
}
public async Task BulkUpdateReturnWarningDetailsAsync(List<ReturnWarningDetailsIndex> details, int maxRetries = 3)
{
if (details.Count == 0) return;
//构建批量更新操作描述符
var desc = new BulkDescriptor().UpdateMany(details,
(u, detail) => u.Id(detail.Id)
.Index(detail.IndexName)
.Script(s => s.Source(@"
ctx._source.ReturnWarningRuleId = param.ReturnWarningRuleId;
ctx._source.WarningId = param.WarningId;
ctx._source.Version = param.Version;
ctx._source.ReturnTimeSpan = param.ReturnTimeSpan;
//ctx._source.NotifyModes = param.NotifyModes;
ctx._source.NotifyUsers = param.NotifyUsers;
ctx._source.SubSystemId = param.SubSystemId;
ctx._source.CustomId = param.CustomId;
ctx._source.OrderId = param.OrderId;
ctx._source.OrderNo = param.OrderNo;
ctx._source.OrderType = param.OrderType;
ctx._source.TrackStatusId = param.TrackStatusId;
ctx._source.TrackStatus = param.TrackStatus;
ctx._source.CompareFields = param.CompareFields;
ctx._source.Extra = param.Extra;
ctx._source.TrackContentId = param.TrackContentId;
ctx._source.TrackContent = param.TrackContent;
ctx._source.TrackCode = param.TrackCode;
ctx._source.TrackPlace = param.TrackPlace;
ctx._source.TrackTime = param.TrackTime;
ctx._source.TrackTimeZone = param.TrackTimeZone;
ctx._source.TrackCreateTime = param.TrackCreateTime;
ctx._source.PushTrackStatus = param.PushTrackStatus;
ctx._source.PushTrackCode = param.PushTrackCode;
ctx._source.PushTrackContent = param.PushTrackContent;
ctx._source.PushTrackEnContent = param.PushTrackEnContent;
ctx._source.TrackReturnTime = param.TrackReturnTime;
ctx._source.RetryCount = param.RetryCount;
ctx._source.Status = param.Status;
ctx._source.ActualReturnTimeSpan = param.ActualReturnTimeSpan;
ctx._source.SystemReturnTimeSpan = param.SystemReturnTimeSpan;
ctx._source.TrackCreateTimeSpan = param.TrackCreateTimeSpan;
ctx._source.CreateTime = param.CreateTime;
ctx._source.UpdateTime = param.UpdateTime;
").Params(p => p
.Add("ReturnWarningRuleId", detail.ReturnWarningRuleId)
.Add("WarningId", detail.WarningId)
.Add("Version", detail.Version)
.Add("ReturnTimeSpan", detail.ReturnTimeSpan)
//.Add("NotifyModes", detail.NotifyModes)
.Add("NotifyUsers", detail.NotifyUsers)
.Add("SubSystemId", detail.SubSystemId)
.Add("CustomId", detail.CustomId)
.Add("OrderId", detail.OrderId)
.Add("OrderNo", detail.OrderNo)
.Add("OrderType", detail.OrderType)
.Add("TrackStatusId", detail.TrackStatusId)
.Add("TrackStatus", detail.TrackStatus)
.Add("CompareFields", detail.CompareFields)
.Add("Extra", detail.Extra)
.Add("TrackContentId", detail.TrackContentId)
.Add("TrackContent", detail.TrackContent)
.Add("TrackCode", detail.TrackCode)
.Add("TrackPlace", detail.TrackPlace)
.Add("TrackTime", detail.TrackTime)
.Add("TrackTimeZone", detail.TrackTimeZone)
.Add("TrackCreateTime", detail.TrackCreateTime)
.Add("PushTrackStatus", detail.PushTrackStatus)
.Add("PushTrackCode", detail.PushTrackCode)
.Add("PushTrackContent", detail.PushTrackContent)
.Add("PushTrackEnContent", detail.PushTrackEnContent)
.Add("TrackReturnTime", detail.TrackReturnTime)
.Add("RetryCount", detail.RetryCount)
.Add("Status", detail.Status)
.Add("ActualReturnTimeSpan", detail.ActualReturnTimeSpan)
.Add("SystemReturnTimeSpan", detail.SystemReturnTimeSpan)
.Add("TrackCreateTimeSpan", detail.TrackCreateTimeSpan)
.Add("CreateTime", detail.CreateTime)
.Add("UpdateTime", detail.UpdateTime)
)
)
);
await PollyHelper.RetryPollyExecAsync(() => _client.BulkAsync(desc), response =>
{
if (response.IsValid) // 认为成功
return true;
if (response.ServerError.Status == 409) //版本冲突认为失败,则重试
return false;
throw new InvalidOperationException($"ES更新失败:{details.Count}条,原因:{response.DebugInformation}。");
});
}
public async Task InsertReturnWarningDetailsAsync(ReturnWarningDetailsIndex detail)
{
var indexName = $"{GlobalConst.ReturnWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
detail.IndexName = indexName;
var r = await _client.IndexAsync(detail, s => s.Index(indexName));
if (!r.IsValid)
{
throw new InvalidOperationException($"回传预警明细新增失败,{detail},原因:{r.DebugInformation}。");
}
}
public async Task BulkInsertReturnWarningDetailsAsync(List<ReturnWarningDetailsIndex> details, int maxRetries = 3)
{
// 按天写入es
var indexName = $"{GlobalConst.ReturnWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
details.ForEach(x => x.IndexName = indexName);
var r = await _client.IndexManyAsync(details, indexName);
if (!r.IsValid)
{
throw new InvalidOperationException($"回传预警明细新增失败,原因:{r.DebugInformation}。");
}
}
public async Task InsertReturnMessageRecordAsync(ReturnMessageRecordIndex detail)
{
var indexName = $"{GlobalConst.ReturnMessageRecordIndex}-{DateTime.Now:yyyy.MM.dd}";
detail.IndexName = indexName;
var r = await _client.IndexAsync(detail, s => s.Index(indexName));
if (!r.IsValid)
{
throw new InvalidOperationException($"回传日志新增失败,{detail},原因:{r.DebugInformation}。");
}
}
public async Task BulkInsertReturnMessageRecordAsync(List<ReturnMessageRecordIndex> details, int maxRetries = 3)
{
// 按天写入es
var indexName = $"{GlobalConst.ReturnMessageRecordIndex}-{DateTime.Now:yyyy.MM.dd}";
details.ForEach(x => x.IndexName = indexName);
var r = await _client.IndexManyAsync(details, indexName);
if (!r.IsValid)
{
throw new InvalidOperationException($"回传日志新增失败,原因:{r.DebugInformation}。");
}
}
#endregion
#region 完整
public async Task<UnifyPageResultDto<CompleteWarningDetailsIndex>> GetPageCompleteWarningDetailsAsync(GetPageCompleteWarningDetailsInputVO input)
{
var musts = ListWrapperFactory.CreateListWrapper<CompleteWarningDetailsIndex, GetPageCompleteWarningDetailsInputVO>(input);
var orderNos = input.OrderNos?.Split(',');
musts.AddIf(x => x.SubSystemId > 0, c => c.Term(f => f.SubSystemId, input.SubSystemId));
musts.AddIf(_ => orderNos?.Length > 0, c => c.Terms(f => f.Field(d => d.OrderNo.Suffix("keyword")).Terms(orderNos)));
musts.AddIf(x => x.OrderType > 0, c => c.Term(f => f.OrderType, input.OrderType));
musts.AddIf(x => x.Status > 0, c => c.Term(f => f.Status, input.Status));
musts.AddIf(x => x.CustomId > 0, c => c.Term(f => f.CustomId, input.CustomId));
musts.AddIf(x => x.MissingTrackStatusId > 0, c => c.Match(f => f.Field(d => d.MissingTrackStatusIds).Query(input.MissingTrackStatusId.ToString())));
musts.AddIf(x => x.WarningCreateTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.CreateTime).LessThanOrEquals(input.WarningCreateTimeStart)));
musts.AddIf(x => x.WarningCreateTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.CreateTime).LessThanOrEquals(input.WarningCreateTimeEnd)));
musts.AddIf(x => x.WarningHandleTimeStart.HasValue, c => c.DateRange(r => r.Field(f => f.ProcessedTime).LessThanOrEquals(input.WarningHandleTimeStart)));
musts.AddIf(x => x.WarningHandleTimeEnd.HasValue, c => c.DateRange(r => r.Field(f => f.ProcessedTime).LessThanOrEquals(input.WarningHandleTimeEnd)));
// 模糊匹配userId
musts.AddIf(x => x.NotifyUserId.HasValue, c => c.Match(f => f.Field(d => d.NotifyUsers).Query(input.NotifyUserId.ToString())));
var resp = await _client.SearchAsync<CompleteWarningDetailsIndex>(x => x
.Index(GlobalConst.CompleteWarningDetailsIndex)
.Query(q => q.Bool(b => b.Must(musts)))
.From((input.PageIndex - 1) * input.PageSize)
.Size(input.PageSize));
return new UnifyPageResultDto<CompleteWarningDetailsIndex>(resp.ToIdList(), input.PageIndex, input.PageSize, (int) resp.Total);
}
public async Task UpdateCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail)
{
var r = await _client.UpdateAsync<CompleteWarningDetailsIndex, object>(detail.Id,
u => u.Index(detail.IndexName)
.Doc(new
{
detail.WarningId,
detail.CompleteWarningRuleId,
detail.Version,
//detail.NotifyModes,
detail.NotifyUsers,
detail.CheckPointTrackStatusId,
detail.MissingTrackStatusIds,
detail.SubSystemId,
detail.CustomId,
detail.OrderId,
detail.OrderNo,
detail.OrderType,
detail.Status,
detail.CreateTime,
detail.ProcessedTime,
}));
}
public async Task BulkUpdateCompleteWarningDetailsAsync(List<CompleteWarningDetailsIndex> details, int maxRetries = 3)
{
if (details.Count == 0) return;
//构建批量更新操作描述符
var desc = new BulkDescriptor().UpdateMany(details,
(u, detail) => u.Id(detail.Id)
.Index(detail.IndexName)
.Script(s => s.Source(@"
ctx._source.WarningId = param.WarningId;
ctx._source.CompleteWarningRuleId = param.CompleteWarningRuleId;
ctx._source.Version = param.Version;
//ctx._source.NotifyModes = param.NotifyModes;
ctx._source.NotifyUsers = param.NotifyUsers;
ctx._source.CheckPointTrackStatusId = param.CheckPointTrackStatusId;
ctx._source.MissingTrackStatusIds = param.MissingTrackStatusIds;
ctx._source.SubSystemId = param.SubSystemId;
ctx._source.CustomId = param.CustomId;
ctx._source.OrderId = param.OrderId;
ctx._source.OrderNo = param.OrderNo;
ctx._source.OrderType = param.OrderType;
ctx._source.Status = param.Status;
ctx._source.CreateTime = param.CreateTime;
ctx._source.ProcessedTime = param.ProcessedTime;
")
.Params(p => p
.Add("WarningId", detail.WarningId)
.Add("CompleteWarningRuleId", detail.CompleteWarningRuleId)
.Add("Version", detail.Version)
//.Add("NotifyModes", detail.NotifyModes)
.Add("NotifyUsers", detail.NotifyUsers)
.Add("CheckPointTrackStatusId", detail.CheckPointTrackStatusId)
.Add("MissingTrackStatusIds", detail.MissingTrackStatusIds)
.Add("SubSystemId", detail.SubSystemId)
.Add("CustomId", detail.CustomId)
.Add("OrderId", detail.OrderId)
.Add("OrderNo", detail.OrderNo)
.Add("OrderType", detail.OrderType)
.Add("Status", detail.Status)
.Add("CreateTime", detail.CreateTime)
.Add("ProcessedTime", detail.ProcessedTime)
)
)
);
await PollyHelper.RetryPollyExecAsync(() => _client.BulkAsync(desc), response =>
{
if (response.IsValid) // 认为成功
return true;
if (response.ServerError.Status == 409) //版本冲突认为失败,则重试
return false;
throw new InvalidOperationException($"ES更新失败:{details.Count}条,原因:{response.DebugInformation}。");
});
}
public async Task InsertCompleteWarningDetailsAsync(CompleteWarningDetailsIndex detail)
{
var indexName = $"{GlobalConst.CompleteWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
detail.IndexName = indexName;
var r = await _client.IndexAsync(detail, s => s.Index(indexName));
if (!r.IsValid)
{
throw new InvalidOperationException($"完整预警明细新增失败,{detail},原因:{r.DebugInformation}。");
}
}
public async Task BulkInsertCompleteWarningDetailsAsync(List<CompleteWarningDetailsIndex> details, int maxRetries = 3)
{
// 按天写入es
var indexName = $"{GlobalConst.CompleteWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
details.ForEach(x => x.IndexName = indexName);
var r = await _client.IndexManyAsync(details, indexName);
if (!r.IsValid)
{
throw new InvalidOperationException($"完整预警明细新增失败,原因:{r.DebugInformation}。");
}
}
#endregion
public async Task CreateAliasAsync()
{
var indexName1 = $"{GlobalConst.TransportWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
var indexName2 = $"{GlobalConst.ReturnWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
var indexName3 = $"{GlobalConst.CompleteWarningDetailsIndex}-{DateTime.Now:yyyy.MM.dd}";
var indexName4 = $"{GlobalConst.ReturnMessageRecordIndex}-{DateTime.Now:yyyy.MM.dd}";
var exists1 = await _client.Indices.ExistsAsync(indexName1);
if (!exists1.Exists)
{
await _client.Indices.CreateAsync(indexName1);
await _client.MapAsync<TransportWarningDetailsIndex>(m => m.Index(indexName1).AutoMap());
}
var exists2 = await _client.Indices.ExistsAsync(indexName2);
if (!exists2.Exists)
{
await _client.Indices.CreateAsync(indexName2);
await _client.MapAsync<ReturnWarningDetailsIndex>(m => m.Index(indexName2).AutoMap());
}
var exists3 = await _client.Indices.ExistsAsync(indexName3);
if (!exists3.Exists)
{
await _client.Indices.CreateAsync(indexName3);
await _client.MapAsync<CompleteWarningDetailsIndex>(m => m.Index(indexName3).AutoMap());
}
var exists4 = await _client.Indices.ExistsAsync(indexName4);
if (!exists4.Exists)
{
await _client.Indices.CreateAsync(indexName4);
await _client.MapAsync<ReturnMessageRecordIndex>(m => m.Index(indexName4).AutoMap());
}
var r = await _client.Indices.BulkAliasAsync(b =>
b.Add(a => a.Alias(GlobalConst.TransportWarningDetailsIndex).Index(indexName1))
.Add(a => a.Alias(GlobalConst.ReturnWarningDetailsIndex).Index(indexName2))
.Add(a => a.Alias(GlobalConst.CompleteWarningDetailsIndex).Index(indexName3))
.Add(a => a.Alias(GlobalConst.ReturnMessageRecordIndex).Index(indexName4))
);
}
}

View File

@ -0,0 +1,217 @@
using SJZY.Track.Domain.Aggregates.WarningAggregate;
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;
using SJZY.Track.Domain.Extensions;
namespace SJZY.Track.Repository.Repositories;
public sealed class WarningRuleRepository : BasicRepository<WarningRuleEntity>, IWarningRuleRepository, ITransientDependency
{
#region 规则主体
public async Task<bool> CheckNameDuplicateAsync(int id, int subsystemId, int customId, string name)
{
var entity = await Context.Queryable<WarningRuleEntity>()
.Where(x => x.SubSystemId == subsystemId &&
x.CustomId == customId
&& string.Equals(x.Name, name))
.FirstAsync();
// 如果是新增,则要求不能重复添加 subsystemId+customId+name三者都相同的
if (id == 0)
return entity != null;
// 如果是修改,则要求查出来的和要修改的是同一个,否则视为重复
return entity.Id != id;
}
public async Task<int> UpsertReturnIdAsync(WarningRuleEntity entity)
{
if (entity.Id == 0)
{
return await Context.Insertable(entity)
.ExecuteReturnIdentityAsync();
}
var isUpdated = await Context.Updateable(entity)
.ExecuteCommandHasChangeAsync();
// 指定了id更新失败
if (!isUpdated)
{
throw new Exception($"{entity}更新失败");
}
return entity.Id;
}
public async Task<string> UpdateVersionAsync(WarningRuleEntity entity)
{
var version = VersionGenerate.GenVersion();
await Context.Updateable<WarningRuleEntity>()
.Where(x => x.Id == entity.Id)
.SetColumns(x => x.Version, version)
.ExecuteCommandHasChangeAsync();
return version;
}
public Task<List<WarningRuleEntity>> GetWarningRuleListAsync(int? subsystemId, string? keyword, bool? isEnabled, int? warningType)
{
return Context.Queryable<WarningRuleEntity>()
.WhereIF(subsystemId.HasValue, x => x.SubSystemId == subsystemId!.Value)
// todo: 客户/kpi名称 改成客户下拉
// .WhereIF(!string.IsNullOrWhiteSpace(keyword), x => x.Name.Contains(keyword!) || x.CustomName.Contains(keyword!))
.WhereIF(isEnabled.HasValue, x => x.IsEnabled == isEnabled!.Value)
.WhereIF(warningType.HasValue, x => x.WarningType == warningType!.Value)
.ToListAsync();
}
public async Task<WarningRuleEntity?> GetWarningRuleForEnabledAsync(int subSystemId, int customId, WarningRuleType warningType)
{
var warningRules = await Context.Queryable<WarningRuleEntity>()
.Where(x => x.SubSystemId == subSystemId)
.Where(x => x.CustomId == customId)
.Where(x => x.WarningType == (int) warningType)
.ToListAsync();
return warningRules.FirstOrDefault();
}
public async Task<WarningRuleEntity?> GetWarningRuleByIdAsync(int id, WarningRuleType? warningType = null)
{
var result = await Context.Queryable<WarningRuleEntity>()
.Where(x => x.Id == id)
.WhereIF(warningType.HasValue, x => x.WarningType == (int) warningType!.Value)
.ToListAsync();
return result.FirstOrDefault();
}
#endregion
#region 运输时效预警规则
public Task<List<TransportWarningSceneEntity>> GetTransportSceneAsync(int warningId)
{
return Context.Queryable<TransportWarningSceneEntity>()
.Where(x => x.WarningId == warningId)
.ToListAsync();
}
public async Task<TransportWarningSceneEntity?> GetTransportSceneAsync(int warningId, int sceneId)
{
var result = await Context.Queryable<TransportWarningSceneEntity>()
.Where(x => x.WarningId == warningId && x.Id == sceneId)
.ToListAsync();
return result.FirstOrDefault();
}
public Task<List<TransportWarningSceneRuleItemEntity>> GetTransportSceneRuleItemsAsync(int warningId, int sceneId)
{
return Context.Queryable<TransportWarningSceneRuleItemEntity>()
.Where(x => x.WarningId == warningId && x.TransportWarningSceneId == sceneId)
.ToListAsync();
}
public async Task<int> UpsertTransportSceneReturnIdAsync(TransportWarningSceneEntity entity)
{
if (entity.Id == 0)
{
return await Context.Insertable(entity)
.ExecuteReturnIdentityAsync();
}
var isUpdated = await Context.Updateable(entity)
.ExecuteCommandHasChangeAsync();
// 指定了id更新失败
if (!isUpdated)
{
throw new Exception($"{entity}更新失败");
}
return entity.Id;
}
public async Task<int> BulkUpdateTransportSceneRuleItemsAsync(List<TransportWarningSceneRuleItemEntity> entities)
{
return await Context.Updateable(entities)
.ExecuteCommandAsync();
}
public Task<int> BulkInsertTransportSceneRuleItemsAsync(List<TransportWarningSceneRuleItemEntity> entities)
{
return Context.Insertable(entities)
.ExecuteCommandAsync();
}
public Task<int> DeleteTransportSceneRuleItemsAsync(HashSet<int> ruleItemIds)
{
return Context.Deleteable<TransportWarningSceneRuleItemEntity>()
.Where(x => ruleItemIds.Contains(x.Id))
.ExecuteCommandAsync();
}
#endregion
#region 回传时效预警规则
public Task<List<ReturnWarningRuleItemEntity>> GetReturnRuleItemsAsync(int warningId)
{
return Context.Queryable<ReturnWarningRuleItemEntity>()
.Where(x => x.WarningId == warningId)
.ToListAsync();
}
public Task<int> BulkInsertReturnRuleItemsAsync(List<ReturnWarningRuleItemEntity> entities)
{
return Context.Insertable(entities)
.ExecuteCommandAsync();
}
public async Task<int> BulkUpdateReturnRuleItemsAsync(List<ReturnWarningRuleItemEntity> entities)
{
return await Context.Updateable(entities)
.ExecuteCommandAsync();
}
public Task<int> DeleteReturnRuleItemsAsync(HashSet<int> ruleItemIds)
{
return Context.Deleteable<ReturnWarningRuleItemEntity>()
.Where(x => ruleItemIds.Contains(x.Id))
.ExecuteCommandAsync();
}
#endregion
#region 完整预警规则
public Task<List<CompleteWarningRuleItemEntity>> GetCompleteRuleItemsAsync(int warningId)
{
return Context.Queryable<CompleteWarningRuleItemEntity>()
.Where(x => x.WarningId == warningId)
.ToListAsync();
}
public async Task<int> BulkUpdateCompleteRuleItemsAsync(List<CompleteWarningRuleItemEntity> entities)
{
return await Context.Updateable(entities)
.ExecuteCommandAsync();
}
public Task<int> BulkInsertCompleteRuleItemsAsync(List<CompleteWarningRuleItemEntity> entities)
{
return Context.Insertable(entities)
.ExecuteCommandAsync();
}
public Task<int> DeleteCompleteRuleItemsAsync(HashSet<int> ruleItemIds)
{
return Context.Deleteable<CompleteWarningRuleItemEntity>()
.Where(x => ruleItemIds.Contains(x.Id))
.ExecuteCommandAsync();
}
#endregion
}

View File

@ -0,0 +1,159 @@
using System.Linq.Expressions;
using SJZY.Track.Domain.Aggregates.WarningAggregate;
using SJZY.Track.Domain.Aggregates.WarningAggregate.Return;
using SJZY.Track.Domain.Aggregates.WarningAggregate.Transport;
namespace SJZY.Track.Repository.Repositories;
public sealed class WarningTaskRepository : BasicRepository<WarningNotifyTaskEntity>, IWarningTaskRepository, ITransientDependency
{
//public ISqlSugarClient Context { get; set; }
public WarningTaskRepository()
{
//Context = SqlsugarScopeBasic.GetContextSafely("default");
}
#region 预警通知任务
public Task<List<WarningNotifyTaskEntity>> ScanMayNeedExecutedTaskAsync()
{
return Context.Queryable<WarningNotifyTaskEntity>()
.Where(x => x.IsClosed == false)
.ToListAsync();
}
public Task<List<WarningNotifyTaskEntity>> GetWarningNotifyTaskAsync(Expression<Func<WarningNotifyTaskEntity, bool>> expression)
{
return Context.Queryable<WarningNotifyTaskEntity>()
.Where(expression)
.ToListAsync();
}
public async Task<bool> AddWarningNotifyTaskAsync(WarningNotifyTaskEntity entity)
{
return await Context.Insertable(entity).ExecuteCommandAsync() > 0;
}
public Task<int> BulkInsertWarningNotifyTaskAsync(List<WarningNotifyTaskEntity> entities)
{
return Context.Insertable(entities)
.ExecuteCommandAsync();
}
public Task<int> CloseWarningNotifyTaskAsync(Expression<Func<WarningNotifyTaskEntity, bool>> expression)
{
return Context.Updateable<WarningNotifyTaskEntity>()
.Where(expression)
.SetColumns(x => x.IsClosed, true)
.ExecuteCommandAsync();
}
public Task<bool> CloseWarningNotifyTaskAsync(WarningNotifyTaskEntity entity)
{
if (entity.IsClosed) return Task.FromResult(false);
return Context.Updateable(entity)
.SetColumns(x => x.IsClosed, true)
.ExecuteCommandHasChangeAsync();
}
#endregion
#region 回传预警_重试推送任务
public Task<List<ReturnWarningRetryPushTaskEntity>> ScanReturnWarningRetryPushTaskAsync()
{
return Context.Queryable<ReturnWarningRetryPushTaskEntity>()
.Where(x => x.IsClosed == false)
.ToListAsync();
}
public Task<List<ReturnWarningRetryPushTaskEntity>> GetReturnWarningRetryPushTaskAsync(Expression<Func<ReturnWarningRetryPushTaskEntity, bool>> expression)
{
return Context.Queryable<ReturnWarningRetryPushTaskEntity>()
.Where(expression)
.ToListAsync();
}
public async Task<bool> AddReturnWarningRetryPushTaskAsync(ReturnWarningRetryPushTaskEntity entity)
{
return await Context.Insertable(entity)
.ExecuteCommandAsync() > 0;
}
public Task<int> BulkInsertReturnWarningRetryPushTaskAsync(List<ReturnWarningRetryPushTaskEntity> entities)
{
return Context.Insertable(entities)
.ExecuteCommandAsync();
}
public Task<int> CloseReturnWarningRetryPushTaskAsync(Expression<Func<ReturnWarningRetryPushTaskEntity, bool>> expression)
{
return Context.Updateable<ReturnWarningRetryPushTaskEntity>()
.Where(expression)
.SetColumns(x => x.IsClosed, true)
.ExecuteCommandAsync();
}
public Task<bool> CloseReturnWarningRetryPushTaskAsync(ReturnWarningRetryPushTaskEntity entity)
{
if (entity.IsClosed) return Task.FromResult(false);
return Context.Updateable(entity)
.SetColumns(x => x.IsClosed, true)
.ExecuteCommandHasChangeAsync();
}
#endregion
#region 运输预警_预警明细生成任务
public Task<List<TransportWarningDetailsGenerateTaskEntity>> ScanTransportWarningDetailsGenerateTaskAsync()
{
return Context.Queryable<TransportWarningDetailsGenerateTaskEntity>()
.Where(x => x.IsClosed == false)
.ToListAsync();
}
public Task<List<TransportWarningDetailsGenerateTaskEntity>> GetTransportWarningDetailsGenerateTaskAsync(Expression<Func<TransportWarningDetailsGenerateTaskEntity, bool>> expression)
{
return Context.Queryable<TransportWarningDetailsGenerateTaskEntity>()
.Where(expression)
.ToListAsync();
}
public async Task<bool> AddTransportWarningDetailsGenerateTaskAsync(TransportWarningDetailsGenerateTaskEntity entity)
{
return await Context.Insertable(entity)
.ExecuteCommandAsync() > 0;
}
public Task<int> BulkInsertTransportWarningDetailsGenerateTaskAsync(List<TransportWarningDetailsGenerateTaskEntity> entities)
{
return Context.Insertable(entities)
.ExecuteCommandAsync();
}
public Task<int> BulkUpdateTransportWarningDetailsGenerateTaskAsync(List<TransportWarningDetailsGenerateTaskEntity> entities)
{
return Context.Updateable(entities)
.ExecuteCommandAsync();
}
public Task<int> CloseTransportWarningDetailsGenerateTaskAsync(Expression<Func<TransportWarningDetailsGenerateTaskEntity, bool>> expression)
{
return Context.Updateable<TransportWarningDetailsGenerateTaskEntity>()
.Where(expression)
.SetColumns(x => x.IsClosed, true)
.ExecuteCommandAsync();
}
public Task<bool> CloseTransportWarningDetailsGenerateTaskAsync(TransportWarningDetailsGenerateTaskEntity entity)
{
if (entity.IsClosed) return Task.FromResult(false);
return Context.Updateable(entity)
.SetColumns(x => x.IsClosed, true)
.ExecuteCommandHasChangeAsync();
}
#endregion
}