From 4e4dbbeb5fe89515321a6728883e9a4564d25283 Mon Sep 17 00:00:00 2001 From: moyongzhen <2534173414@qq.com> Date: Wed, 13 Mar 2024 10:20:26 +0800 Subject: [PATCH 01/60] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Order/GetPageTrackOrderInputVO.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs b/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs index fe8e3fb1..c4eacc83 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs @@ -39,16 +39,6 @@ namespace SJZY.Track.Domain.Dtos.Order /// public string? OrderNos { get; set; } - /// - /// 订单类型 - /// - public int? TrackOrderType { get; set; } - - /// - /// 客户id - /// - public int? CustomerId { get; set; } - /// /// 创建时间开始 /// From b7c4256e521eaa1484bd15f76bce0cea549d863f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Wed, 20 Mar 2024 15:56:56 +0800 Subject: [PATCH 02/60] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/ProvideServices/GetPageTrackOrderInput.cs | 10 ---------- .../Dtos/Order/GetPageTrackOrderInputVO.cs | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs index 07469365..e37b69bd 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs @@ -22,16 +22,6 @@ public class GetPageTrackOrderInput : PageInfoInput /// public int TabType { get; set; } - /// - /// 订单类型 - /// - public int? TrackOrderType { get; set; } - - /// - /// 客户id - /// - public int? CustomerId { get; set; } - ///// ///// 当tab选中 0 默认不传 1 直接写死传值 [1,4] 2 传 [2,4] ///// diff --git a/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs b/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs index f742309b..5f164841 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs @@ -32,16 +32,6 @@ /// public List? OrderNos { get; set; } - /// - /// 订单类型 - /// - public int? TrackOrderType { get; set; } - - /// - /// 客户id - /// - public int? CustomerId { get; set; } - /// /// 创建时间开始 /// From a02e4ca8b230a37c161201613a466767eb5a97a2 Mon Sep 17 00:00:00 2001 From: moyongzhen <2534173414@qq.com> Date: Fri, 29 Mar 2024 11:17:35 +0800 Subject: [PATCH 03/60] debug --- .../ProvideServices/OrderService.Link.cs | 112 ------------------ .../Services/ProvideServices/OrderService.cs | 101 ++++++++++++++++ 2 files changed, 101 insertions(+), 112 deletions(-) delete mode 100644 src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs deleted file mode 100644 index 88eb9530..00000000 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs +++ /dev/null @@ -1,112 +0,0 @@ -using DotNetCore.CAP; -using SJZY.Track.Application.Contract.Dtos.ProvideServices; -using SJZY.Track.Application.Contract.Events; -using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Queries; - -namespace SJZY.Track.Application.Services.ProvideServices; - -/// -/// 订单关联服务 -/// -public partial class OrderService -{ - private readonly IBasicQuery _orderLinkQuery; - private readonly ICapPublisher _capPublisher; - - /// - /// 关联、解除关联订单 - /// - /// - /// - /// - [HttpPost("Order/Link")] - public async Task LinkOrderAsync(LinkOrderInput input) - { - var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new - { - x.Id, x.SubSystemId - }); - if (order == default) - { - throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); - } - - //tips:循环关联问题再消费时解决 - if (input.OrderType == input.LinkOrderType) - { - throw new BusinessException(message: "不能同级关联"); - } - - if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true; - - // 单号去重,去空,去自己 - input.LinkOrderNos = input.LinkOrderNos - .Where(x => !x.IsNullOrWhiteSpace() && x != input.OrderNo) - .Distinct().ToList(); - - // 解绑 - if (!input.IsLink) return await UnLinkOrderAsync(input); - - // 关联订单 - var linkedOrderIds = await DoLinkOrderAsync(input, order.Id); - - // 补轨迹 - if (linkedOrderIds.Count > 0) - { - await _capPublisher.PublishAsync(GlobalConst.OrderLinkAfterFillTrack, new OrderLinkAfterFillTrackEvent - { - OrderId = order.Id, - SubSystemId = order.SubSystemId, - LinkedOrderIds = linkedOrderIds, - }); - } - - return true; - } - - private async Task> DoLinkOrderAsync(LinkOrderInput input, int orderId) - { - // 获取已关联的订单 - var linkOrderNos = await _orderLinkQuery.GetListAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && x.LinkOrderType == input.LinkOrderType, - x => x.LinkOrderNo); - - // 计算出未关联的订单 - var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos); - - // 过滤掉不存在的订单 - var canLinkOrders = await _orderRepository.GetListAsync(x => - x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), - x => new { x.Id, x.OrderNo }); - - if (canLinkOrders.Count == 0) return new List(); - - await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity - { - OrderId = orderId, - OrderNo = input.OrderNo, - OrderType = input.OrderType, - LinkOrderId = x.Id, - LinkOrderNo = x.OrderNo, - LinkOrderType = input.LinkOrderType - }).ToList()); - - return canLinkOrders.Select(x => x.Id).ToList(); - } - - private async Task UnLinkOrderAsync(LinkOrderInput input) - { - var unLinkIds = await _orderLinkQuery.GetListAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && - x.LinkOrderType == input.LinkOrderType && input.LinkOrderNos.Contains(x.LinkOrderNo), - x => x.Id); - - // real del - await _orderRepository.UnLinkByIdsAsync(unLinkIds); - - return true; - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs index 712b775c..ce4913bc 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs @@ -1,7 +1,9 @@ using DotNetCore.CAP; using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Queries; using SJZY.UserCenter.HttpApi.Services; @@ -15,6 +17,9 @@ namespace SJZY.Track.Application.Services.ProvideServices; public partial class OrderService : ApplicationService, IOrderService { private readonly IOrderRepository _orderRepository; + private readonly IBasicQuery _orderLinkQuery; + private readonly ICapPublisher _capPublisher; + public OrderService(IOrderRepository orderRepository, IBasicQuery orderLinkQuery, ICapPublisher capPublisher) @@ -79,4 +84,100 @@ public partial class OrderService : ApplicationService, IOrderService order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); await _orderRepository.UpdateOrderAsync(order); } + + /// + /// 关联、解除关联订单 + /// + /// + /// + /// + [HttpPost("Order/Link")] + public async Task LinkOrderAsync(LinkOrderInput input) + { + var order = await _orderRepository.GetFirstAsync(x => + x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new + { + x.Id, + x.SubSystemId + }); + if (order == default) + { + throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); + } + + //tips:循环关联问题再消费时解决 + if (input.OrderType == input.LinkOrderType) + { + throw new BusinessException(message: "不能同级关联"); + } + + if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true; + + // 单号去重,去空,去自己 + input.LinkOrderNos = input.LinkOrderNos + .Where(x => !x.IsNullOrWhiteSpace() && x != input.OrderNo) + .Distinct().ToList(); + + // 解绑 + if (!input.IsLink) return await UnLinkOrderAsync(input); + + // 关联订单 + var linkedOrderIds = await DoLinkOrderAsync(input, order.Id); + + // 补轨迹 + if (linkedOrderIds.Count > 0) + { + await _capPublisher.PublishAsync(GlobalConst.OrderLinkAfterFillTrack, new OrderLinkAfterFillTrackEvent + { + OrderId = order.Id, + SubSystemId = order.SubSystemId, + LinkedOrderIds = linkedOrderIds, + }); + } + + return true; + } + + private async Task> DoLinkOrderAsync(LinkOrderInput input, int orderId) + { + // 获取已关联的订单 + var linkOrderNos = await _orderLinkQuery.GetListAsync(x => + x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && x.LinkOrderType == input.LinkOrderType, + x => x.LinkOrderNo); + + // 计算出未关联的订单 + var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos); + + // 过滤掉不存在的订单 + var canLinkOrders = await _orderRepository.GetListAsync(x => + x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), + x => new { x.Id, x.OrderNo }); + + if (canLinkOrders.Count == 0) return new List(); + + await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity + { + OrderId = orderId, + OrderNo = input.OrderNo, + OrderType = input.OrderType, + LinkOrderId = x.Id, + LinkOrderNo = x.OrderNo, + LinkOrderType = input.LinkOrderType + }).ToList()); + + return canLinkOrders.Select(x => x.Id).ToList(); + } + + private async Task UnLinkOrderAsync(LinkOrderInput input) + { + var unLinkIds = await _orderLinkQuery.GetListAsync(x => + x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && + x.LinkOrderType == input.LinkOrderType && input.LinkOrderNos.Contains(x.LinkOrderNo), + x => x.Id); + + // real del + await _orderRepository.UnLinkByIdsAsync(unLinkIds); + + return true; + } } \ No newline at end of file From f24168b62da902dad61d02462ae46009f3306a14 Mon Sep 17 00:00:00 2001 From: moyongzhen <2534173414@qq.com> Date: Fri, 29 Mar 2024 11:40:00 +0800 Subject: [PATCH 04/60] Revert "debug" This reverts commit a02e4ca8b230a37c161201613a466767eb5a97a2. --- .../ProvideServices/OrderService.Link.cs | 112 ++++++++++++++++++ .../Services/ProvideServices/OrderService.cs | 101 ---------------- 2 files changed, 112 insertions(+), 101 deletions(-) create mode 100644 src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs new file mode 100644 index 00000000..88eb9530 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs @@ -0,0 +1,112 @@ +using DotNetCore.CAP; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Queries; + +namespace SJZY.Track.Application.Services.ProvideServices; + +/// +/// 订单关联服务 +/// +public partial class OrderService +{ + private readonly IBasicQuery _orderLinkQuery; + private readonly ICapPublisher _capPublisher; + + /// + /// 关联、解除关联订单 + /// + /// + /// + /// + [HttpPost("Order/Link")] + public async Task LinkOrderAsync(LinkOrderInput input) + { + var order = await _orderRepository.GetFirstAsync(x => + x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new + { + x.Id, x.SubSystemId + }); + if (order == default) + { + throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); + } + + //tips:循环关联问题再消费时解决 + if (input.OrderType == input.LinkOrderType) + { + throw new BusinessException(message: "不能同级关联"); + } + + if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true; + + // 单号去重,去空,去自己 + input.LinkOrderNos = input.LinkOrderNos + .Where(x => !x.IsNullOrWhiteSpace() && x != input.OrderNo) + .Distinct().ToList(); + + // 解绑 + if (!input.IsLink) return await UnLinkOrderAsync(input); + + // 关联订单 + var linkedOrderIds = await DoLinkOrderAsync(input, order.Id); + + // 补轨迹 + if (linkedOrderIds.Count > 0) + { + await _capPublisher.PublishAsync(GlobalConst.OrderLinkAfterFillTrack, new OrderLinkAfterFillTrackEvent + { + OrderId = order.Id, + SubSystemId = order.SubSystemId, + LinkedOrderIds = linkedOrderIds, + }); + } + + return true; + } + + private async Task> DoLinkOrderAsync(LinkOrderInput input, int orderId) + { + // 获取已关联的订单 + var linkOrderNos = await _orderLinkQuery.GetListAsync(x => + x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && x.LinkOrderType == input.LinkOrderType, + x => x.LinkOrderNo); + + // 计算出未关联的订单 + var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos); + + // 过滤掉不存在的订单 + var canLinkOrders = await _orderRepository.GetListAsync(x => + x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), + x => new { x.Id, x.OrderNo }); + + if (canLinkOrders.Count == 0) return new List(); + + await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity + { + OrderId = orderId, + OrderNo = input.OrderNo, + OrderType = input.OrderType, + LinkOrderId = x.Id, + LinkOrderNo = x.OrderNo, + LinkOrderType = input.LinkOrderType + }).ToList()); + + return canLinkOrders.Select(x => x.Id).ToList(); + } + + private async Task UnLinkOrderAsync(LinkOrderInput input) + { + var unLinkIds = await _orderLinkQuery.GetListAsync(x => + x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && + x.LinkOrderType == input.LinkOrderType && input.LinkOrderNos.Contains(x.LinkOrderNo), + x => x.Id); + + // real del + await _orderRepository.UnLinkByIdsAsync(unLinkIds); + + return true; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs index ce4913bc..712b775c 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs @@ -1,9 +1,7 @@ using DotNetCore.CAP; using SJZY.Track.Application.Contract.Dtos.ProvideServices; -using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Queries; using SJZY.UserCenter.HttpApi.Services; @@ -17,9 +15,6 @@ namespace SJZY.Track.Application.Services.ProvideServices; public partial class OrderService : ApplicationService, IOrderService { private readonly IOrderRepository _orderRepository; - private readonly IBasicQuery _orderLinkQuery; - private readonly ICapPublisher _capPublisher; - public OrderService(IOrderRepository orderRepository, IBasicQuery orderLinkQuery, ICapPublisher capPublisher) @@ -84,100 +79,4 @@ public partial class OrderService : ApplicationService, IOrderService order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); await _orderRepository.UpdateOrderAsync(order); } - - /// - /// 关联、解除关联订单 - /// - /// - /// - /// - [HttpPost("Order/Link")] - public async Task LinkOrderAsync(LinkOrderInput input) - { - var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new - { - x.Id, - x.SubSystemId - }); - if (order == default) - { - throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); - } - - //tips:循环关联问题再消费时解决 - if (input.OrderType == input.LinkOrderType) - { - throw new BusinessException(message: "不能同级关联"); - } - - if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true; - - // 单号去重,去空,去自己 - input.LinkOrderNos = input.LinkOrderNos - .Where(x => !x.IsNullOrWhiteSpace() && x != input.OrderNo) - .Distinct().ToList(); - - // 解绑 - if (!input.IsLink) return await UnLinkOrderAsync(input); - - // 关联订单 - var linkedOrderIds = await DoLinkOrderAsync(input, order.Id); - - // 补轨迹 - if (linkedOrderIds.Count > 0) - { - await _capPublisher.PublishAsync(GlobalConst.OrderLinkAfterFillTrack, new OrderLinkAfterFillTrackEvent - { - OrderId = order.Id, - SubSystemId = order.SubSystemId, - LinkedOrderIds = linkedOrderIds, - }); - } - - return true; - } - - private async Task> DoLinkOrderAsync(LinkOrderInput input, int orderId) - { - // 获取已关联的订单 - var linkOrderNos = await _orderLinkQuery.GetListAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && x.LinkOrderType == input.LinkOrderType, - x => x.LinkOrderNo); - - // 计算出未关联的订单 - var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos); - - // 过滤掉不存在的订单 - var canLinkOrders = await _orderRepository.GetListAsync(x => - x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), - x => new { x.Id, x.OrderNo }); - - if (canLinkOrders.Count == 0) return new List(); - - await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity - { - OrderId = orderId, - OrderNo = input.OrderNo, - OrderType = input.OrderType, - LinkOrderId = x.Id, - LinkOrderNo = x.OrderNo, - LinkOrderType = input.LinkOrderType - }).ToList()); - - return canLinkOrders.Select(x => x.Id).ToList(); - } - - private async Task UnLinkOrderAsync(LinkOrderInput input) - { - var unLinkIds = await _orderLinkQuery.GetListAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && - x.LinkOrderType == input.LinkOrderType && input.LinkOrderNos.Contains(x.LinkOrderNo), - x => x.Id); - - // real del - await _orderRepository.UnLinkByIdsAsync(unLinkIds); - - return true; - } } \ No newline at end of file From 3a179e743622f10a645fe55a49fe58b69fef88a6 Mon Sep 17 00:00:00 2001 From: moyongzhen <2534173414@qq.com> Date: Fri, 29 Mar 2024 14:14:19 +0800 Subject: [PATCH 05/60] =?UTF-8?q?=E5=AF=B9=E5=A4=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=8C=85=20=20unifyResultDto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/IOrderService.cs | 6 +++--- .../ProvideServices/OrderService.Link.cs | 17 +++++++++-------- .../Services/ProvideServices/OrderService.cs | 11 ++++++----- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Services/IOrderService.cs b/src/SJZY.Track.Application.Contract/Services/IOrderService.cs index 0dd34413..adff3b24 100644 --- a/src/SJZY.Track.Application.Contract/Services/IOrderService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IOrderService.cs @@ -10,19 +10,19 @@ public interface IOrderService : IRemoteService /// /// /// - Task UpsertAsync(UpsertOrderInput input); + Task UpsertAsync(UpsertOrderInput input); /// /// 删除订单 /// /// /// - Task DeleteOrderAsync(DeleteOrderInput input); + Task DeleteOrderAsync(DeleteOrderInput input); /// /// 关联订单 /// /// /// - Task LinkOrderAsync(LinkOrderInput input); + Task LinkOrderAsync(LinkOrderInput input); } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs index 88eb9530..7226ee0f 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs @@ -22,13 +22,14 @@ public partial class OrderService /// /// [HttpPost("Order/Link")] - public async Task LinkOrderAsync(LinkOrderInput input) + public async Task LinkOrderAsync(LinkOrderInput input) { var order = await _orderRepository.GetFirstAsync(x => x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new - { - x.Id, x.SubSystemId - }); + { + x.Id, + x.SubSystemId + }); if (order == default) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); @@ -40,7 +41,7 @@ public partial class OrderService throw new BusinessException(message: "不能同级关联"); } - if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true; + if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return new UnifyResultDto(true); // 单号去重,去空,去自己 input.LinkOrderNos = input.LinkOrderNos @@ -64,7 +65,7 @@ public partial class OrderService }); } - return true; + return new UnifyResultDto(true); } private async Task> DoLinkOrderAsync(LinkOrderInput input, int orderId) @@ -97,7 +98,7 @@ public partial class OrderService return canLinkOrders.Select(x => x.Id).ToList(); } - private async Task UnLinkOrderAsync(LinkOrderInput input) + private async Task UnLinkOrderAsync(LinkOrderInput input) { var unLinkIds = await _orderLinkQuery.GetListAsync(x => x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && @@ -107,6 +108,6 @@ public partial class OrderService // real del await _orderRepository.UnLinkByIdsAsync(unLinkIds); - return true; + return new UnifyResultDto(true); } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs index 712b775c..d562ef9b 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs @@ -30,7 +30,7 @@ public partial class OrderService : ApplicationService, IOrderService /// /// [HttpPost("Order/Upsert")] - public async Task UpsertAsync(UpsertOrderInput input) + public async Task UpsertAsync(UpsertOrderInput input) { if (input.Templates.Count == 0) throw new BusinessException(message: "至少有一个模板"); var order = await _orderRepository.GetFirstAsync(x => @@ -39,7 +39,8 @@ public partial class OrderService : ApplicationService, IOrderService { // 订单已存在则视为更新 await UpdateOrderAsync(input, order); - return "更新成功"; + + return new UnifyResultDto() { Code = "200", Msg = "操作成功", Data = "创建成功" }; } order = ObjectMapper.Map(input); @@ -48,7 +49,7 @@ public partial class OrderService : ApplicationService, IOrderService order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); await _orderRepository.CreateOrderAsync(order); - return "创建成功"; + return new UnifyResultDto() { Code = "200", Msg = "操作成功", Data = "新增成功" }; } /// @@ -58,7 +59,7 @@ public partial class OrderService : ApplicationService, IOrderService /// /// [HttpPost("Order/Delete")] - public async Task DeleteOrderAsync(DeleteOrderInput input) + public async Task DeleteOrderAsync(DeleteOrderInput input) { var orderId = await _orderRepository.GetFirstAsync(x => x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => x.Id); @@ -69,7 +70,7 @@ public partial class OrderService : ApplicationService, IOrderService await _orderRepository.DeleteOrderAsync(orderId); - return true; + return new UnifyResultDto(true); } private async Task UpdateOrderAsync(UpdateOrderInput input, OrderEntity order) From ba095bd49849dadfd467bf194a823be9bc2a56a5 Mon Sep 17 00:00:00 2001 From: dingenwen <543338760@qq.com> Date: Mon, 1 Apr 2024 16:48:26 +0800 Subject: [PATCH 06/60] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SJZY.Track.Api/appsettings.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SJZY.Track.Api/appsettings.json b/src/SJZY.Track.Api/appsettings.json index b88d44ad..676973d6 100644 --- a/src/SJZY.Track.Api/appsettings.json +++ b/src/SJZY.Track.Api/appsettings.json @@ -7,9 +7,7 @@ "Env": "DEV", "Namespace": "Dev", "MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080", - "ConfigServer": [ - "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080" - ] + "ConfigServer": [ "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080" ] } }, "Kestrel": { From bebb84bddacdc95876a1f4cf32d924fd443c07c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Fri, 12 Apr 2024 21:40:17 +0800 Subject: [PATCH 07/60] =?UTF-8?q?change=EF=BC=9A=E5=8F=8C=E8=AE=A2?= =?UTF-8?q?=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EventHandlers/TrackUpsertEventHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs index 81e954fe..0ce9623c 100644 --- a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs @@ -27,7 +27,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] - [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] + [CapSubscribe(GlobalConst.TrackUpsertForRefreshSubscribe, Group = GlobalConst.TrackUpsertForRefreshSubscribe)] public async Task ConsumerAsync(TrackUpsertEvent @event) { var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); From 77d2275afa6fb9bf4c958da6d4829ba18cb9115c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Mon, 15 Apr 2024 09:03:04 +0800 Subject: [PATCH 08/60] =?UTF-8?q?fix=EF=BC=9Aorder=20link=20query=20logic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EventHandlers/TrackDeleteEventHandler.cs | 2 +- .../EventHandlers/TrackUpsertEventHandler.cs | 2 +- src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs | 5 +++++ src/SJZY.Track.Repository/Repositories/OrderRepository.cs | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs index ea6698fb..fc413d98 100644 --- a/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs @@ -42,7 +42,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderIds); foreach (var orderId in @event.OrderIds) { - foreach (var group in linkedOrders.Where(x => x.OrderId == orderId) + foreach (var group in linkedOrders.Where(x => x.OwnerOrderId == orderId) .GroupBy(x => x.SubSystemId)) { var nextEvent = @event.DeepCopy(); diff --git a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs index 0ce9623c..81d7e461 100644 --- a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs @@ -46,7 +46,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe foreach (var order in @event.OrderIdentifiers) { // 理论上小包在这不会分组 - foreach (var group in linkedOrders.Where(x => x.OrderId == order.OrderId) + foreach (var group in linkedOrders.Where(x => x.OwnerOrderId == order.OrderId) .GroupBy(x => x.SubSystemId)) { var nextEvent = @event.DeepCopy(); diff --git a/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs b/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs index c6eea835..5b81e796 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs @@ -2,6 +2,11 @@ public class LinkedOrderVO { + /// + /// 被关联订单id + /// + public int OwnerOrderId { get; set; } + /// /// 关联订单id /// diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index 5e78fc5f..93edf756 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -74,6 +74,7 @@ AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;"); .Where(a => orderIds.Contains(a.OrderId)) .Select((a, b) => new LinkedOrderVO { + OwnerOrderId = a.OrderId, OrderId = b.Id, OrderNo = b.OrderNo, OrderType = b.OrderType, From ff49c0879a56d1b06e8ff5fa9ddee6c64fbb51b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Mon, 15 Apr 2024 09:25:34 +0800 Subject: [PATCH 09/60] =?UTF-8?q?change=EF=BC=9A=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=95=86=E7=A9=BA=E6=95=B0=E6=8D=AE=E7=94=A8--=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EventHandlers/TrackDeleteEventHandler.cs | 2 +- .../EventHandlers/TrackUpsertEventHandler.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs index fc413d98..cf076a42 100644 --- a/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs @@ -49,7 +49,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe nextEvent.Visited.AddRange(@event.OrderIds); nextEvent.TrackCodes = @event.TrackCodes; nextEvent.SubSystemId = group.Key; - + nextEvent.OrderIds = group.Select(x => x.OrderId).ToArray(); // 不同子系统需要做内容映射 if (@event.SubSystemId != nextEvent.SubSystemId) diff --git a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs index 81d7e461..192a1b87 100644 --- a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs @@ -60,9 +60,9 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe }).ToArray(); nextEvent.TrackRefreshData = new TrackRefreshStruct { - ServiceProviderName = @event.TrackRefreshData.ServiceProviderName, - OriginTrackContent = @event.TrackRefreshData.OriginTrackContent, - OriginTrackData = @event.TrackRefreshData.OriginTrackData, + ServiceProviderName = @event.TrackRefreshData.ServiceProviderName ?? GlobalConst.EmptyString, + OriginTrackContent = @event.TrackRefreshData.OriginTrackContent ?? GlobalConst.EmptyString, + OriginTrackData = @event.TrackRefreshData.OriginTrackData ?? GlobalConst.EmptyString, // tips:一定要重置为false,父级订单的完成不会使得关联订单完成,关联单也必须由刷新来完成或手动设置完成!! IsCompleted = false }; From f62c73a93e1cdb4d1e37e5c9b3123cfee07dc47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Mon, 15 Apr 2024 09:58:07 +0800 Subject: [PATCH 10/60] format --- .../EventHandlers/TrackDeleteEventHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs index cf076a42..ccd4d0d5 100644 --- a/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/SJZY.Track.Application/EventHandlers/TrackDeleteEventHandler.cs @@ -84,6 +84,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe new TrackChangeAfterUpdateOrderEvent { OrderIds = @event.OrderIds, + TrackCode = @event.TrackCodes.JoinAsString(","), IsDelete = true }); } From 49bf17694458678b0655fc3ea20d3933f7500f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Mon, 15 Apr 2024 10:10:37 +0800 Subject: [PATCH 11/60] publish --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d53fbc8a..342ca2ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ ## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. +## files generated by popular Visual Studio add-ons.. # User-specific files *.suo From 97a71aaffa6bd89e23078bf7eee6af7965c8f34e Mon Sep 17 00:00:00 2001 From: moyongzhen <2534173414@qq.com> Date: Mon, 15 Apr 2024 10:23:14 +0800 Subject: [PATCH 12/60] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=B8=80=E8=87=B4=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/ProvideServices/GetPageTrackOrderInput.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs index 2ddf9d9a..d9c87ab0 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs @@ -22,6 +22,16 @@ public class GetPageTrackOrderInput : PageInfoInput /// public int TabType { get; set; } + /// + /// 订单类型 + /// + public int? TrackOrderType { get; set; } + + /// + /// 客户id + /// + public int? CustomerId { get; set; } + ///// ///// 当tab选中 0 默认不传 1 直接写死传值 [1,4] 2 传 [2,4] ///// From a7d5c8c9cc44a11020f6765091efa8d2913cc352 Mon Sep 17 00:00:00 2001 From: moyongzhen <2534173414@qq.com> Date: Mon, 15 Apr 2024 10:26:13 +0800 Subject: [PATCH 13/60] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Options/GetCamsUrlOptions.cs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/SJZY.Track.Application/Options/GetCamsUrlOptions.cs diff --git a/src/SJZY.Track.Application/Options/GetCamsUrlOptions.cs b/src/SJZY.Track.Application/Options/GetCamsUrlOptions.cs deleted file mode 100644 index 82677724..00000000 --- a/src/SJZY.Track.Application/Options/GetCamsUrlOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using SJZY.Expand.ABP.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SJZY.Track.Application.Options -{ - public class GetCamsUrlOptions : IOptionAutoInjection - { - /// - /// 2.5URL - /// - public string? Cams25URL { get; set; } - } -} From 8ce26fe28d6454e04fb08d573638d1b8f5cefe07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Tue, 16 Jul 2024 15:10:26 +0800 Subject: [PATCH 14/60] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SJZY.Track.Application/SjzyTrackApplicationModule.cs | 1 - .../Repositories/TrackDetailsRepository.cs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs b/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs index 10394daa..0dfe7b1e 100644 --- a/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs +++ b/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs @@ -99,7 +99,6 @@ namespace SJZY.Track.Application options.SucceedMessageExpiredAfter = configuration.GetValue("CAP:SucceedMessageExpiredAfter"); options.FallbackWindowLookbackSeconds = configuration.GetValue("CAP:FallbackWindowLookbackSeconds"); - options.EnableSubscriberParallelExecute = true; options.UseDashboard(dashboardOptions => { diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs index 4f798cb2..33c278d9 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs @@ -1,4 +1,5 @@ using Nest; +using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Expand.ElasticSearch.Services; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Consts; @@ -175,7 +176,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract Date: Fri, 19 Jul 2024 15:28:26 +0800 Subject: [PATCH 15/60] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E6=95=B0=E6=8D=AE=E5=BA=93=E4=B8=BADEV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + src/SJZY.Track.Api/appsettings.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d53fbc8a..2138f2b3 100644 --- a/.gitignore +++ b/.gitignore @@ -189,3 +189,4 @@ UpgradeLog*.htm FakesAssemblies/ logs/ /.vs +.idea/ diff --git a/src/SJZY.Track.Api/appsettings.json b/src/SJZY.Track.Api/appsettings.json index d69cb0c1..6f7fc2b9 100644 --- a/src/SJZY.Track.Api/appsettings.json +++ b/src/SJZY.Track.Api/appsettings.json @@ -5,7 +5,7 @@ "Apollo": { "AppId": "SJZY.Track.Configuration", "Env": "DEV", - "Namespace": "Test", + "Namespace": "DEV", "MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080", "ConfigServer": [ "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080" ] } From 895e12762d545e189bb8e4226474cec123655312 Mon Sep 17 00:00:00 2001 From: "DESKTOP-S2TSHMH\\BSI" Date: Wed, 24 Jul 2024 08:54:56 +0800 Subject: [PATCH 16/60] =?UTF-8?q?feat:=20=E9=A2=84=E8=AD=A6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/ProvideServices/UpdateOrderInput.cs | 15 ++ .../SJZY.Track.Application.Contract.csproj | 3 + .../Services/IForewarningNotifyService.cs | 30 +++ .../Services/IKpiAreaCacheService.cs | 6 + .../Services/INotifyService.cs | 6 + .../Services/IRuleFactorCacheService.cs | 32 +++ .../AutoMapper/ForewarningMapperProfile.cs | 48 ++++ ...TrackChangeAfterUpdateOrderEventHandler.cs | 43 +++- .../Helpers/ForewarningFactorHelper.cs | 58 +++++ .../SJZY.Track.Application.csproj | 4 + .../ForewarningNotifyService.cs | 236 ++++++++++++++++++ .../ForewarningServices/ForewarningService.cs | 128 ++++++++++ .../KpiAreaCacheService.cs | 46 ++++ .../ForewarningServices/KpiAreaService.cs | 131 ++++++++++ .../RuleFactorCacheService.cs | 195 +++++++++++++++ .../Services/Notifies/NotifyService.cs | 12 + .../Forewarning/CreateRuleFactorValidation.cs | 33 +++ .../Forewarning/FactorItemDtoValidator.cs | 6 + .../Forewarning/RuleTrackStateDtoValidator.cs | 15 ++ .../ForewarningAggregate/FactorItemModel.cs | 16 ++ .../ForewarningAggregate/IForewarningList.cs | 8 + .../IRuleCollectRepository.cs | 13 + .../IRuleFactorRepository.cs | 10 + .../ForewarningAggregate/IRuleRepository.cs | 12 + .../ForewarningAggregate/RuleAreaEntity.cs | 6 + .../ForewarningAggregate/RuleCollectEntity.cs | 110 ++++++++ .../ForewarningAggregate/RuleEntity.cs | 60 +++++ .../ForewarningAggregate/RuleFactorEntity.cs | 55 ++++ .../RuleTrackStateModel.cs | 24 ++ .../Aggregates/KPIAreaAggregate.cs | 6 + .../KPIAreaAggregate/IKpiAreaRepository.cs | 68 +++++ .../KPIAreaAggregate/RuleAreaEntity.cs | 50 ++++ .../KPIAreaAggregate/RuleAreaInfoEntity.cs | 71 ++++++ .../Aggregates/OrderAggregate/OrderEntity.cs | 18 ++ .../Consts/GlobalConst.ES.cs | 5 + .../Consts/GlobalConst.Redis.cs | 15 ++ .../Forewarning/AddRuleAreaInfoRequest.cs | 20 ++ .../Dtos/Forewarning/AreaDto.cs | 9 + .../Dtos/Forewarning/AreaInfoDto.cs | 35 +++ .../Dtos/Forewarning/CreateRuleAreaRequest.cs | 18 ++ .../Dtos/Forewarning/CreateRuleRequest.cs | 65 +++++ .../Dtos/Forewarning/FactorItemDto.cs | 16 ++ .../Dtos/Forewarning/ForewarningOrderModel.cs | 30 +++ .../Dtos/Forewarning/ForewarningRule.cs | 26 ++ .../Forewarning/IForewarningFactorValue.cs | 16 ++ .../Dtos/Forewarning/KpiAreaInfo.cs | 6 + .../Forewarning/ModifyTimelinessRequest.cs | 34 +++ .../Dtos/Forewarning/QueryAreaInfoRequest.cs | 6 + .../Dtos/Forewarning/QueryAreaRequest.cs | 14 ++ .../Forewarning/QueryForewarningRequest.cs | 24 ++ .../QueryForewarningRuleRequest.cs | 19 ++ .../Dtos/Forewarning/RuleCollectDto.cs | 22 ++ .../Dtos/Forewarning/RuleCollectRequest.cs | 7 + .../Dtos/Forewarning/RuleFactor.cs | 37 +++ .../Dtos/Forewarning/RuleInfoModel.cs | 42 ++++ .../Dtos/Forewarning/RuleNotifyValue.cs | 40 +++ .../Dtos/Forewarning/RuleTrackStateDto.cs | 24 ++ .../Forewarning/UpdateRuleAreaInfoRequest.cs | 22 ++ .../Dtos/Forewarning/UpdateRuleAreaRequest.cs | 17 ++ src/SJZY.Track.Domain/Enums/RuleFactorType.cs | 38 +++ .../SJZY.Track.Domain.csproj | 5 + .../Repositories/KpiAreaInfoRepository.cs | 6 + .../Repositories/KpiAreaRepository.cs | 103 ++++++++ .../Repositories/RuleCollectRepository.cs | 50 ++++ .../Repositories/RuleFactorRepository.cs | 53 ++++ .../Repositories/RuleRepository.cs | 53 ++++ 66 files changed, 2450 insertions(+), 1 deletion(-) create mode 100644 src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs create mode 100644 src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs create mode 100644 src/SJZY.Track.Application.Contract/Services/INotifyService.cs create mode 100644 src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs create mode 100644 src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs create mode 100644 src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs create mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs create mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs create mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs create mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs create mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs create mode 100644 src/SJZY.Track.Application/Services/Notifies/NotifyService.cs create mode 100644 src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs create mode 100644 src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs create mode 100644 src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/FactorItemModel.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleAreaEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleFactor.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs create mode 100644 src/SJZY.Track.Domain/Enums/RuleFactorType.cs create mode 100644 src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs create mode 100644 src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs create mode 100644 src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs create mode 100644 src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs create mode 100644 src/SJZY.Track.Repository/Repositories/RuleRepository.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs index ebb47f17..14e2fdc3 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs @@ -51,4 +51,19 @@ public class UpdateOrderInput : OrderNoInfo /// 订单航班信息 /// public List FlightInfos { get; set; } = new(); + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 是否转运 + /// + public bool? IsTransfer { get; set; } + + /// + /// 产品编码 + /// + public string? ProductCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj b/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj index 7a7f7902..f2e2a7a3 100644 --- a/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj +++ b/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj @@ -12,5 +12,8 @@ + + + diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs new file mode 100644 index 00000000..f76891a1 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs @@ -0,0 +1,30 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Services; + +/// +/// 预警通知服务接口定义。 +/// 提供创建、删除预警通知和发送通知的功能。 +/// +public interface IForewarningNotifyService +{ + /// + /// 创建预警通知。 + /// + /// 预警订单模型。 + /// 创建操作的结果,以整数形式返回。 + Task CreateForewarningNotify(ForewarningOrderModel order); + + /// + /// 删除预警通知。 + /// + /// 预警订单模型。 + /// 删除操作的结果,以整数形式返回。 + Task DeleteForewarningNotify(ForewarningOrderModel order); + + /// + /// 发送通知。 + /// + /// 通知间隔时间,以分钟为单位。 + void SendNotification(int intervalMinute); +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs new file mode 100644 index 00000000..5713a2d8 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Contract.Services; + +public interface IKpiAreaCacheService +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/INotifyService.cs b/src/SJZY.Track.Application.Contract/Services/INotifyService.cs new file mode 100644 index 00000000..54b8a368 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/INotifyService.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Contract.Services; + +public interface INotifyService +{ + void SendNotification(string body); +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs new file mode 100644 index 00000000..41eb2171 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs @@ -0,0 +1,32 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Services; + +/// +/// 定义了与规则因子缓存相关的服务接口。 +/// +public interface IRuleFactorCacheService +{ + /// + /// 获取所有因子收集的规则。 + /// + /// 规则数组。 + Task GetAllFactorCollect(); + + /// + /// 获取所有规则因子。 + /// + /// 规则因子实体列表。 + Task> GetAllRuleFactor(); + + /// + /// 清除因子缓存。 + /// + void ClearFactorCache(); + + /// + /// 清除规则缓存。 + /// + void ClearRuleCache(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs new file mode 100644 index 00000000..b905d38d --- /dev/null +++ b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs @@ -0,0 +1,48 @@ +using AutoMapper; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.AutoMapper; + +public class ForewarningMapperProfile :Profile +{ + public ForewarningMapperProfile() + { + CreateMap(MemberList.None); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(MemberList.None); + CreateMap(MemberList.None) + .ForMember(dest => dest.Country, opt => opt.MapFrom(src => src.Country)) + .ForMember(dest => dest.Province, opt => opt.MapFrom(src => src.Province)) + .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) + .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) + .ForMember(dest => dest.RightPostcode, opt => opt.MapFrom(src => src.RightPostCode)) + .ForMember(dest => dest.AreaId, opt => opt.MapFrom(src => src.AreaId)); + + CreateMap(MemberList.None) + .ForMember(dest => dest.SubSystemId, opt => opt.MapFrom(src => src.SystemId)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)); + + CreateMap(MemberList.None) + .ForMember(dest => dest.Country, opt => opt.MapFrom(src => src.Country)) + .ForMember(dest => dest.Province, opt => opt.MapFrom(src => src.Province)) + .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) + .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) + .ForMember(dest => dest.RightPostcode, opt => opt.MapFrom(src => src.RightPostCode)); + + CreateMap(MemberList.None) + .ForMember(dest => dest.RuleId, opt => opt.MapFrom(src => src.RuleId)) + .ForMember(dest => dest.Tracks, opt => opt.MapFrom(src => src.Tracks)) + .ForMember(dest => dest.FactorItems, opt => opt.MapFrom(src => src.FactorItems)) + .ForMember(dest => dest.CargoTypes, opt => opt.MapFrom(src => src.CargoTypes)) + .ForMember(dest => dest.Months, opt => opt.MapFrom(src => src.Months.Select(m => m.ToString()))) + .ForMember(dest => dest.IsTransit, opt => opt.MapFrom(src => src.IsTransit.Select(i => i == 1))) + .ForMember(dest => dest.Areas, opt => opt.MapFrom(src => src.Areas)) + .ForMember(dest => dest.DeparturePorts, opt => opt.MapFrom(src => src.DeparturePorts)) + .ForMember(dest => dest.ProductCodes, opt => opt.MapFrom(src => src.ProductCodes)); + + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index c8f184ae..7a371e49 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -1,8 +1,10 @@ using DotNetCore.CAP; using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.CAP.EventHandlers; @@ -11,12 +13,15 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa { private readonly IOrderRepository _orderRepository; private readonly ITrackDetailsRepository _trackDetailsRepository; + private readonly IForewarningNotifyService _forewarningNotifyService; public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, - ITrackDetailsRepository trackDetailsRepository) + ITrackDetailsRepository trackDetailsRepository, + IForewarningNotifyService forewarningNotifyService) { _orderRepository = orderRepository; _trackDetailsRepository = trackDetailsRepository; + _forewarningNotifyService = forewarningNotifyService; } [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] @@ -68,4 +73,40 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa x.LatestTrackTimeZone }); } + + private ForewarningOrderModel OrderToForewarningOrderModel(OrderEntity order) +{ + return new ForewarningOrderModel + { + Id = order.Id, + Track = DetermineTrackBasedOnOrderDetails(order), + SystemId = order.SubSystemId, + CustomerId = order.CustomId, + CargoType = order.CargoType, + Month = order.CreateTime.Month, + Area = DetermineAreaBasedOnOrderDetails(order), + IsTransit = order.IsTransfer, + DeparturePort = order.LeavePort, + ProductCode = order.ProductCode + }; +} + +// Placeholder methods for deriving or converting values. You'll need to implement these based on your specific logic. +private int DetermineTrackBasedOnOrderDetails(OrderEntity order) +{ + // Implement logic to determine Track + return default; +} + +private int? DetermineMonthBasedOnOrderDetails(OrderEntity order) +{ + // Implement logic to determine Month + return default; +} + +private int? DetermineAreaBasedOnOrderDetails(OrderEntity order) +{ + // Implement logic to determine Area + return default; +} } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs new file mode 100644 index 00000000..c88ec276 --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs @@ -0,0 +1,58 @@ +using JetBrains.Annotations; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +namespace SJZY.Track.Application.Helpers; + +public class ForewarningFactorHelper +{ + public static RuleCollectEntity[] GetFactorItem([NotNull]RuleFactorEntity ruleFactors) + { + var total = Factorial(ruleFactors); + var ruleCollect = AllocateFactor(total,ruleFactors.RuleId); + Assignment(ruleCollect,total,ruleFactors.CargoTypes,(item,value)=>item.CargoType=value); + Assignment(ruleCollect,total,ruleFactors.Months,(item,value)=>item.Month=value); + Assignment(ruleCollect,total,ruleFactors.Areas,(item,value)=>item.Area=value); + Assignment(ruleCollect,total,ruleFactors.IsTransit,(item,value)=>item.IsTransit=value); + Assignment(ruleCollect,total,ruleFactors.DeparturePorts,(item,value)=>item.DeparturePort=value); + Assignment(ruleCollect,total,ruleFactors.ProductCodes,(item,value)=>item.ProductCode=value); + return ruleCollect.ToArray(); + } + + private static void Assignment(Span ruleCollect,int total,IReadOnlyList values,Action action) + { + if (values.Count == 0) + { + return; + } + + var segment = total / values.Count; + for(int index=0;index AllocateFactor(int total,int ruleId) + { + + Span factors = new RuleCollectEntity[total]; + for (int index = 0; index < total; index++) + { + factors[index] = new RuleCollectEntity() + { + RuleId = ruleId + }; + } + return factors; + } + + internal static int Factorial(RuleFactorEntity ruleFactors) + { + return ruleFactors.CargoTypes.Count*ruleFactors.Months.Count*ruleFactors.Areas.Count*ruleFactors.IsTransit.Count*ruleFactors.DeparturePorts.Count*ruleFactors.ProductCodes.Count; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/SJZY.Track.Application.csproj b/src/SJZY.Track.Application/SJZY.Track.Application.csproj index 378f50c7..011dd0d7 100644 --- a/src/SJZY.Track.Application/SJZY.Track.Application.csproj +++ b/src/SJZY.Track.Application/SJZY.Track.Application.csproj @@ -29,4 +29,8 @@ + + + + diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs new file mode 100644 index 00000000..d692dad5 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -0,0 +1,236 @@ +using FreeRedis; +using NetTaste; +using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; +using SqlSugar; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +/// +/// 单例服务,用于处理预警通知 +/// +public class ForewarningNotifyService:IForewarningNotifyService,ITransientDependency +{ + private IRuleFactorCacheService _ruleFactorCache; + IReadOnlyDictionary> _ruleGroupDict; + IReadOnlyDictionary> _factorDict; + private IReadOnlyDictionary _rules; + readonly INotifyService _notifyService; + + public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService) + { + _ruleFactorCache = ruleFactorCache; + _notifyService = notifyService; + } + + /// + /// 创建预警通知 + /// + /// 创建预警通知需要的订单信息 + /// 创建的通知总量,0表示没有规则 + public async Task CreateForewarningNotify(ForewarningOrderModel order) + { + var rules = GetRule(order); + if (rules == null || rules.Count == 0) + return 0; + + return await ExecuteRule(rules,order.Id); + } + + /// + /// 清除预警通知 + /// + /// 订单信息 + /// 清理的行数 + public async Task DeleteForewarningNotify(ForewarningOrderModel order) + { + var rules = GetRule(order); + if (rules == null || rules.Count == 0) + return 0; + + var willDeleteMembers = new List(); + foreach (var rule in rules) + { + var allRuleNotities= DeleteNotifyValue(rule, order.Id); + willDeleteMembers.AddRange(allRuleNotities); + } + + await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKeyPrefix, willDeleteMembers.ToArray()); + return willDeleteMembers.Count; + } + + public void SendNotification(int intervalMinute) + { + var currentTimestamp = GetTimestamp(DateTime.Now); + var notifyMembers = RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKeyPrefix, 0, currentTimestamp); + if (notifyMembers == null || notifyMembers.Length == 0) + return; + + var notifyValues = notifyMembers.Select(val => new RuleNotifyValue(val)); + foreach (var notifyValue in notifyValues) + { + if(!_rules.TryGetValue(notifyValue.RuleId, out var rule)) + continue; + + //todo 发送通知 + _notifyService.SendNotification(""); + } + } + + public void ClearCache() + { + _ruleGroupDict = null; + _factorDict = null; + _rules = null; + } + + private List DeleteNotifyValue(ForewarningRule rule,int orderId) + { + var members = new List(); + for(var index=0;index + /// 获取规则 + /// + /// + /// + private List GetRule(ForewarningOrderModel order) + { + if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SystemId), out var factors)) + { + return null; + } + + var keys = GetForewarningKeys(factors, order); + var result = new List< ForewarningRule>(); + + foreach (var item in keys) + { + if (!_ruleGroupDict.TryGetValue(item, out var rules)) + continue; + + var allRules = rules.Where(val=>val.TrackStart <= order.Track && val.TrackEnd >= order.Track); + result.AddRange(allRules); + } + + return result; + } + + private async ValueTask ExecuteRule(List rules,int orderId) + { + var members = new List(); + foreach (var rule in rules) + { + var notifys = ExecuteRule(rule,orderId); + members.AddRange(notifys); + } + + await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKeyPrefix, members.ToArray()); + return members.Count; + } + + private List ExecuteRule(ForewarningRule rule,int orderId) + { + var members = new List(); + var intervalMinute = 60 * ((rule.Timeliness - rule.Remind) / rule.Count);// 间隔多少分钟 + + for(var index=0;index GetForewarningKeys(List factors, IForewarningFactorValue rule) + { + var keys = new List(); + foreach (var factor in factors) + { + var key = GetRuleKey(rule, factor); + keys.Add(key); + } + + return keys; + } + + private async Task Init() + { + var allFactorCollect = await _ruleFactorCache.GetAllFactorCollect(); + var factors = await _ruleFactorCache.GetAllRuleFactor(); + var factorsMap = factors.GroupBy(val=>val.RuleId) + .ToDictionary(val=>val.Key,val=>val.First()); + + _rules = allFactorCollect.ToDictionary(val => val.Id); + + _factorDict = factors.GroupBy(val => GetFactorKey(val.CustomerId,val.SystemId)) + .ToDictionary(val=>val.Key,val=>val.ToList()); + + _ruleGroupDict = allFactorCollect.GroupBy(x => GetRuleKey(x, factorsMap[x.RuleId])) + .ToDictionary(val => val.Key, val => val.ToList()); + } + + private string GetFactorKey(int customerId,int systemId) + { + return $"{customerId}:{systemId}"; + } + + private string GetRuleKey(IForewarningFactorValue rule,RuleFactor factors) + { + var key = ""; + foreach (var factorItem in factors.FactorItems) + { + key+=GetFactorValue(factorItem,rule); + } + + return key; + } + + private string GetFactorValue(FactorItemModel factorItem, IForewarningFactorValue rule) + { + switch (factorItem.FactorType) + { + case RuleFactorType.Areas: + return rule.Area.HasValue ? rule.Area.Value.ToString() : throw new Exception("区域不能为空"); + case RuleFactorType.CargoType: + return rule.CargoType; + case RuleFactorType.DeparturePort: + return rule.DeparturePort; + case RuleFactorType.Month: + return rule.Month.HasValue ? rule.Month.Value.ToString() : throw new Exception("月份不能为空"); + case RuleFactorType.ProductCode: + return rule.ProductCode; + case RuleFactorType.IsTransit: + return rule.IsTransit.HasValue ? "1" : "0"; + // Add additional cases for other RuleFactorTypes as needed + default: + throw new Exception("未知的规则类型"); + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs new file mode 100644 index 00000000..2f660c83 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -0,0 +1,128 @@ +using System.Diagnostics.CodeAnalysis; +using AutoMapper; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SqlSugar; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +[ApiExplorerSettings(GroupName = "预警服务")] +[Route("/ForewarningService")] +public class ForewarningService: ApplicationService +{ + readonly IRuleRepository _ruleRepository; + IRuleFactorRepository _ruleFactorRepository; + private IRuleCollectRepository _ruleCollectRepository; + + public ForewarningService(IRuleRepository ruleRepository + ,IRuleFactorRepository ruleFactorRepository + , IRuleCollectRepository ruleCollectRepository) + { + _ruleRepository = ruleRepository; + _ruleFactorRepository = ruleFactorRepository; + _ruleCollectRepository = ruleCollectRepository; + } + + /// + /// 创建预警模板,存在则更新 + /// + /// + /// + [HttpPost("ModifyForewarning")] + public async ValueTask ModifyForewarning(CreateRuleFactorRequest input) + { + var factors = ObjectMapper.Map(input); + var ruleCollects = ForewarningFactorHelper.GetFactorItem(factors); + + //todo 原子性没有保证,后续可能需要调整 + if (input.RuleId > 0) + { + await _ruleFactorRepository.DeleteByIdAsync(input.RuleId.ToString()); + } + + if (input.RuleId > 0) + { + var ruleTemplate = await _ruleRepository.GetFirstAsync(val=>val.Id == input.RuleId); + if (ruleTemplate == null) + return new UnifyResultDto(false,"规则不存在"); + + ruleTemplate.Name = input.Name; + ruleTemplate.CustomId = input.CustomId; + + await _ruleFactorRepository.IndexDocumentAsync(factors); + await _ruleRepository.UpdateForewarning(ruleTemplate, ruleCollects); + return new UnifyResultDto(true,"保存成功"); + } + + var newRuleTemplate = ObjectMapper.Map(input); + var ruleTemplateId = await _ruleRepository.CreateForewarning(newRuleTemplate, ruleCollects); + factors.Id = ruleTemplateId.ToString(); + return new UnifyResultDto(true,"保存成功"); + } + + /// + /// 修改时效 + /// + [HttpPost("ModifyTimeliness")] + public async ValueTask ModifyTimeliness(ModifyTimelinessRequest input) + { + var ruleIds = input.Items.Select(val=>val.Id).ToList(); + var ruleCollect = await _ruleCollectRepository.GetListAsync(val => ruleIds.Contains(val.Id) && val.RuleId == input.RuleId); + if (ruleCollect == null|| ruleCollect.Count == 0) + throw new BusinessException(message:"规则不存在"); + + var ruleMaps = ruleCollect.ToDictionary(val => val.Id); + var notModifyList = new List(); + foreach (var item in input.Items) + { + if (!ruleMaps.TryGetValue(item.Id, out var rule)) + { + notModifyList.Add(item.Id); + continue; + } + + rule.Remind= item.Remind; + rule.Timeliness = item.Timeliness; + rule.Count = item.Count; + } + + await _ruleCollectRepository.UpdateRangeAsync(ruleCollect,val=>val.RuleId==input.RuleId); + + if (notModifyList.Count > 0) + return new UnifyResultDto(true, $"更新成功,规则{string.Join(",", notModifyList)}不存在"); + + return new UnifyResultDto(true, "更新成功"); + } + + /// + /// 查询预警模板列表 + /// + /// + [HttpPost("QueryForewarning")] + public async Task QueryForewarning(QueryForewarningRequest input) + { + var result = await _ruleRepository.QueryForewarning(input); + return new UnifyResultDto(true, result); + } + + /// + /// 查询预警规则列表 + /// + [HttpPost("QueryForewarningRules")] + public async Task QueryForewarningRules(QueryForewarningRuleRequest input) + { + var result = await _ruleCollectRepository.QueryForewarningRule(input); + return new UnifyResultDto(true, result); + } + + /// + /// 发送预警通知 + /// + [HttpPost("SendForewarningNotification")] + public void SendForewarningNotification() + { + + } + +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs new file mode 100644 index 00000000..65accbcf --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs @@ -0,0 +1,46 @@ +using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +public class KpiAreaCacheService:IKpiAreaCacheService,ITransientDependency +{ + IKpiAreaRepository _kpiAreaRepository; + const string GlobalKpiAreaLockKey = "KpiAreaCacheService_GlobalLock"; + + public KpiAreaCacheService(IKpiAreaRepository kpiAreaRepository) + { + _kpiAreaRepository = kpiAreaRepository; + } + + private string GetKey(int systemId, string country) + { + return $"{GlobalConst.KpiAreaKeyPrefix}:{systemId}:{country}"; + } + + public async Task GetKpiArea(int systemId, string country) + { + var key = GetKey(systemId, country); + var result = RedisHelper.Client.Get(key); + if (result == null) + { + using (var globalLock = RedisHelper.Client.Lock(GlobalKpiAreaLockKey, 10)) + { + result = RedisHelper.Client.Get(key); + if (result != null) return; + + //todo 转换成KpiAreaInfo + var kpiArea =await _kpiAreaRepository.GetAllAreaInfos(); + if (kpiArea == null) + { + return; + } + RedisHelper.Client.Set(key, kpiArea, TimeSpan.FromSeconds(20)); + } + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs new file mode 100644 index 00000000..f87b3109 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -0,0 +1,131 @@ +using AutoMapper; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SqlSugar; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +[ApiExplorerSettings(GroupName = "预警服务")] +[Route("/ForewarningService")] +public class KpiAreaService : ApplicationService +{ + readonly IKpiAreaRepository _ruleAreaRepository; + + public KpiAreaService(IKpiAreaRepository ruleAreaRepository ) + { + _ruleAreaRepository = ruleAreaRepository; + } + + /// + /// 创建分区 + /// + /// + /// 分区id + [HttpPost("KpiArea/CreateKpiArea")] + public async ValueTask CreateKpiArea(CreateRuleAreaRequest input) + { + var ruleAreaEntity = ObjectMapper.Map(input); + var areaId = await _ruleAreaRepository.CreateAreaAsync(ruleAreaEntity); + return new UnifyResultDto(true,areaId, "创建成功"); + } + + /// + /// 添加区域信息 + /// + /// + /// 区域id + [HttpPost("KpiArea/AddAreaInfo")] + public async ValueTask AddAreaInfoAsync(AddRuleAreaInfoRequest input) + { + var ruleAreaEntity = ObjectMapper.Map(input); + var ruleInfoId = await _ruleAreaRepository.AddAreaInfoAsync(ruleAreaEntity); + return new UnifyResultDto(true,ruleInfoId, "添加成功"); + } + + /// + /// 删除分区 + /// + /// 分区id + /// + [HttpDelete("KpiArea/DeleteKpiArea")] + public async ValueTask DeleteKpiArea(int id) + { + await _ruleAreaRepository.DeleteArea(id); + return new UnifyResultDto(true, "删除成功"); + } + + /// + /// 删除分区信息 + /// + /// 分区信息id + /// + [HttpDelete("KpiArea/DeleteKpiAreaInfo")] + public async ValueTask DeleteKpiAreaInfo(int id) + { + await _ruleAreaRepository.DeleteAreaInfo(id); + return new UnifyResultDto(true, "删除成功"); + } + + /// + /// 更新区域信息 + /// + /// + /// + [HttpPost("KpiArea/ModifyKpiArea")] + public async Task ModifyKpiArea(UpdateRuleAreaRequest input) + { + if(input.Id<=0) + return new UnifyResultDto(false,"id不能为空"); + + var ruleArea =await _ruleAreaRepository.GetFirstAsync(val=>val.Id==input.Id); + if(ruleArea==null) + return new UnifyResultDto(false,"未找到该区域"); + + ruleArea.Name = input.Name; + await _ruleAreaRepository.UpdateAsync(ruleArea); + return new UnifyResultDto(true,"更新成功"); + } + + /// + /// 更新区域信息 + /// + /// + /// + [HttpPost("KpiArea/ModifyKpiAreaInfo")] + public async Task ModifyKpiAreaInfo(UpdateRuleAreaInfoRequest input) + { + if(input.Id<=0) + return new UnifyResultDto(false,"id不能为空"); + + //todo 测试不存在id的情况 + RuleAreaInfoEntity areaInfo = await _ruleAreaRepository.GetAreaInfoById(input.Id); + if(areaInfo==null) + return new UnifyResultDto(false,"未找到该区域信息"); + + var ruleAreaEntity = ObjectMapper.Map(input,areaInfo); + await _ruleAreaRepository.UpdateAreaInfoAsync(ruleAreaEntity); + return new UnifyResultDto(true,"更新成功"); + } + + /// + /// 查询分区列表 + /// + /// + /// + [HttpPost("KpiArea/GetKpiAreas")] + public async Task> GetKpiAreas(QueryAreaRequest input) + { + return await _ruleAreaRepository.GetAreas(input); + } + + /// + /// 查询分区列表 + /// + /// + /// + [HttpPost("KpiArea/GetKpiAreaInfos")] + public async Task> GetKpiAreaInfos(QueryAreaInfoRequest query) + { + return await _ruleAreaRepository.GetAreaInfos(query); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs new file mode 100644 index 00000000..6b7ffcb4 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs @@ -0,0 +1,195 @@ +using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +public class RuleFactorCacheService:IRuleFactorCacheService,ITransientDependency +{ + private const string GlobalFactorLockKey = "RuleFactorCacheService_GlobalLock"; + private const string GlobalRuleLockKey = "RuleFactorCacheService_GlobalLock"; + readonly IRuleFactorRepository _ruleFactorRepository; + readonly IRuleCollectRepository _ruleCollectRepository; + readonly IRuleRepository _ruleRepository; + + public RuleFactorCacheService(IRuleFactorRepository ruleFactorRepository, + IRuleCollectRepository ruleCollectRepository, IRuleRepository ruleRepository) + { + _ruleFactorRepository = ruleFactorRepository; + _ruleCollectRepository = ruleCollectRepository; + _ruleRepository = ruleRepository; + } + + private string GetKey() + { + return $"{GlobalConst.RuleFactorKeyPrefix}:allFactor"; + } + + private string GetRuleKey() + { + return $"{GlobalConst.RuleFactorKeyPrefix}:allRule"; + } + + /// + /// 获取所有规则数据 + /// + /// + [NonAction] + public async Task GetAllFactorCollect() + { + + var key = GetRuleKey(); + var result =await RedisHelper.Client.GetAsync(key); + if (result == null) + { + using (var globalLock = RedisHelper.Client.Lock(GlobalRuleLockKey, 10)) + { + result =await RedisHelper.Client.GetAsync(key); + if (result != null) return result; + + var ruleCollect = await _ruleCollectRepository.GetListAsync(val => true); + if (ruleCollect == null || ruleCollect.Count == 0) + { + ForewarningRule[] rules = new ForewarningRule[0]; + await RedisHelper.Client.SetAsync(key,rules , TimeSpan.FromSeconds(20)); + return result; + } + + var ruleList = ruleCollect.SelectMany(RuleEntityToRule); + await RedisHelper.Client.SetAsync(key, ruleList); + return result; + } + } + + return result; + } + + /// + /// 获取所有因素数据 + /// + /// 获取所有因素,返回值可能为空 + [NonAction] + public async Task> GetAllRuleFactor() + { + var key = GetKey(); + var result =await RedisHelper.Client.GetAsync>(key); + if (result == null) + { + using (var globalLock = RedisHelper.Client.Lock(GlobalFactorLockKey, 10)) + { + result =await RedisHelper.Client.GetAsync>(key); + if (result != null) return result; + + result = await GenerateAllRuleFactor(); + if (result == null || result.Count == 0) + { + await RedisHelper.Client.SetAsync(key,new List() , TimeSpan.FromSeconds(20)); + return result; + } + + await RedisHelper.Client.SetAsync(key, result); + return result; + } + } + + return result; + } + + [NonAction] + public void ClearFactorCache() + { + RedisHelper.Client.DelAsync(GetKey()); + } + + [NonAction] + public void ClearRuleCache() + { + RedisHelper.Client.DelAsync(GetRuleKey()); + } + + private async Task> GenerateAllRuleFactor() + { + var factors =await _ruleFactorRepository.GetAllList(); + var ruleTemplate =await _ruleRepository.GetListAsync(val => true); + var ruleMap = ruleTemplate.ToDictionary(val => val.Id); + var result = new List(); + foreach (var item in factors) + { + if(!ruleMap.TryGetValue(item.RuleId,out var rule)) + continue; + var ruleFactors = EntityToRuleFactor(item, rule); + result.AddRange(ruleFactors); + } + + return result; + } + + private ForewarningRule[] RuleEntityToRule(RuleCollectEntity entity) + { + var result = RuleCollectToRule(entity); + if (string.IsNullOrEmpty(entity.Month)) + { + return new ForewarningRule[] { result }; + } + + var months = entity.Month.Split('/'); + var rules = new List(months.Length); + + foreach (var month in months) + { + if (int.TryParse(month, out int monthInt)) + { + var rule = result; + rule.Month = monthInt; + rules.Add(rule); + } + } + + return rules.ToArray(); + } + + private ForewarningRule RuleCollectToRule(RuleCollectEntity entity) + { + return new ForewarningRule + { + Id = entity.Id, + RuleId = entity.RuleId, + Remind = entity.Remind, + Timeliness = entity.Timeliness, + Count = entity.Count, + TrackStart = entity.TrackStart, + TrackEnd = entity.TrackEnd, + CargoType = entity.CargoType, + Month = null, + Area = entity.Area, + IsTransit = entity.IsTransit, + DeparturePort = entity.DeparturePort, + ProductCode = entity.ProductCode + }; + } + + private List EntityToRuleFactor(RuleFactorEntity entity,RuleEntity ruleTemplate) + { + List result = new List(); + foreach (var track in entity.Tracks) + { + var item = new RuleFactor() + { + CustomerId = ruleTemplate.CustomId, + RuleId = ruleTemplate.Id, + NotifyUser = track.NotifyUser, + NotifyTemplate = track.NotifyTemplate, + FactorItems = entity.FactorItems, + End = track.End, + Start = track.Start, + SystemId = ruleTemplate.SubSystemId + }; + result.Add(item); + } + + return result; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/Notifies/NotifyService.cs b/src/SJZY.Track.Application/Services/Notifies/NotifyService.cs new file mode 100644 index 00000000..9365fbc9 --- /dev/null +++ b/src/SJZY.Track.Application/Services/Notifies/NotifyService.cs @@ -0,0 +1,12 @@ +using SJZY.Track.Application.Contract.Services; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.Notifies; + +public class NotifyService:INotifyService, ITransientDependency +{ + public void SendNotification(string body) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs new file mode 100644 index 00000000..0b3fe50a --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs @@ -0,0 +1,33 @@ +using FluentValidation; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Validations.Forewarning; + +public class CreateRuleFactorValidation : AbstractValidator +{ + public CreateRuleFactorValidation() + { + RuleForEach(x => x.Tracks).SetValidator(new RuleTrackStateDtoValidator()); + RuleFor(x => x.FactorItems).NotNull().WithMessage("FactorItems cannot be null."); + + RuleFor(x => x.CargoTypes).NotEmpty().WithMessage("CargoTypes cannot be empty."); + RuleForEach(x => x.CargoTypes).NotEmpty().WithMessage("CargoType cannot be empty."); + + RuleFor(x => x.Months).NotEmpty().WithMessage("Months cannot be empty."); + RuleForEach(x => x.Months) + .ForEach(val=>val.Must(t=>t>0)) + .WithMessage("Each month array must have 12 elements."); + + RuleFor(x => x.IsTransit).NotEmpty().WithMessage("IsTransit cannot be empty."); + RuleForEach(x => x.IsTransit).InclusiveBetween(0, 1).WithMessage("IsTransit must be 0 or 1."); + + RuleFor(x => x.Areas).NotEmpty().WithMessage("Areas cannot be empty."); + RuleForEach(x => x.Areas).GreaterThan(0).WithMessage("Area must be greater than 0."); + + RuleFor(x => x.DeparturePorts).NotEmpty().WithMessage("DeparturePorts cannot be empty."); + RuleForEach(x => x.DeparturePorts).NotEmpty().WithMessage("DeparturePort cannot be empty."); + + RuleFor(x => x.ProductCodes).NotEmpty().WithMessage("ProductCodes cannot be empty."); + RuleForEach(x => x.ProductCodes).NotEmpty().WithMessage("ProductCode cannot be empty."); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs b/src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs new file mode 100644 index 00000000..368e5d63 --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Validations.Forewarning; + +public class FactorItemDtoValidator +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs new file mode 100644 index 00000000..6de8c9b6 --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs @@ -0,0 +1,15 @@ +using FluentValidation; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Validations.Forewarning; + +public class RuleTrackStateDtoValidator : AbstractValidator +{ + public RuleTrackStateDtoValidator() + { + RuleFor(x => x.Start).GreaterThanOrEqualTo(0).WithMessage("Start must be greater than or equal to 0."); + RuleFor(x => x.End).GreaterThanOrEqualTo(0).WithMessage("End must be greater than or equal to 0."); + RuleFor(x => x.NotifyUser).NotEmpty().WithMessage("NotifyUser cannot be empty."); + RuleFor(x => x.NotifyTemplate).NotEmpty().WithMessage("NotifyTemplate cannot be empty."); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/FactorItemModel.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/FactorItemModel.cs new file mode 100644 index 00000000..7df7f7f2 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/FactorItemModel.cs @@ -0,0 +1,16 @@ +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public class FactorItemModel +{ + /// + /// Gets or sets the sort order. + /// + public int Sort { get; set; } + + /// + /// Gets or sets the type of the rule factor. + /// + public RuleFactorType FactorType { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs new file mode 100644 index 00000000..ae0406fe --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs @@ -0,0 +1,8 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IForewarningList +{ + void AddForewarning(int score,int id); + + void DeleteForewarning(int score,int id); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs new file mode 100644 index 00000000..b48a7186 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs @@ -0,0 +1,13 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IRuleCollectRepository:IBasicRepository +{ + /// + /// 查询分页 + /// + /// + /// + Task> QueryForewarningRule(QueryForewarningRuleRequest input); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs new file mode 100644 index 00000000..38b32ef7 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs @@ -0,0 +1,10 @@ +using SJZY.Expand.ElasticSearch.Services; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IRuleFactorRepository:IElasticsearchClientService +{ + Task> GetFactorByIdsAsync(int[] ruleIds); + + Task> GetAllList(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs new file mode 100644 index 00000000..04a32139 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs @@ -0,0 +1,12 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IRuleRepository:IBasicRepository +{ + Task CreateForewarning(RuleEntity rule, RuleCollectEntity[] factorList); + + Task UpdateForewarning(RuleEntity rule, RuleCollectEntity[] factorList); + + Task> QueryForewarning(QueryForewarningRequest input); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleAreaEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleAreaEntity.cs new file mode 100644 index 00000000..c6325956 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleAreaEntity.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public class RuleAreaEntity +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs new file mode 100644 index 00000000..ba4648e2 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs @@ -0,0 +1,110 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_rule_collect")] +public class RuleCollectEntity : IAggregateRoot,ICloneable +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + [SugarColumn(ColumnName = "RuleId")] + public int RuleId { get; set; } + + /// + /// 提醒的时间(小时) + /// + [SugarColumn(ColumnName = "Remind")] + public float Remind { get; set; } + + /// + /// 时效(小时) + /// + [SugarColumn(ColumnName = "Timeliness")] + public float Timeliness { get; set; } + + /// + /// 提醒次数 + /// + [SugarColumn(ColumnName = "Count")] + public int Count { get; set; } + + /// + /// 起始轨迹 + /// + [SugarColumn(ColumnName = "TrackStart", IsNullable = false)] + public int TrackStart { get; set; } + + /// + /// 终止轨迹 + /// + [SugarColumn(ColumnName = "TrackEnd", IsNullable = false)] + public int TrackEnd { get; set; } + + /// + /// 货物类型 + /// + [SugarColumn(ColumnName = "CargoType", Length = 64)] + public string CargoType { get; set; } + + /// + /// 月份 + /// + [SugarColumn(ColumnName = "Month", Length = 25)] + public string Month { get; set; } + + /// + /// 区域 + /// + [SugarColumn(ColumnName = "Area")] + public int? Area { get; set; } + + /// + /// 是否中转 + /// + [SugarColumn(ColumnName = "IsTransit")] + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + [SugarColumn(ColumnName = "DeparturePort")] + public string DeparturePort { get; set; } + + /// + /// 产品编码 + /// + [SugarColumn(ColumnName = "ProductCode")] + public string ProductCode { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId")] + public int UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime")] + public DateTime UpdateTime { get; set; } + + public object Clone() + { + var clone = this.MemberwiseClone(); + return clone; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs new file mode 100644 index 00000000..15439fbf --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs @@ -0,0 +1,60 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_rule")] +public class RuleEntity:IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId")] + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + [SugarColumn(ColumnName = "CustomId")] + public int CustomId { get; set; } + + /// + /// 规则模板名称,KPI名称 + /// + [SugarColumn(ColumnName = "Name", Length = 64)] + public string Name { get; set; } + + /// + /// 规则模板名称,KPI名称 + /// + [SugarColumn(ColumnName = "CustomName", Length = 64)] + public string CustomName { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", IsNullable = false)] + public int UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", IsNullable = false)] + public DateTime UpdateTime { get; set; } + +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs new file mode 100644 index 00000000..b356b062 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs @@ -0,0 +1,55 @@ +using Nest; +using SJZY.Expand.ElasticSearch; +using SJZY.Track.Domain.Consts; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[ElasticsearchType(RelationName = GlobalConst.RuleFactorIndex)] +public class RuleFactorEntity:IdBaseIndex +{ + /// + /// RuleId 表的id + /// + [Keyword(Index = true)] + public int RuleId { get; set; } + + /// + /// 获取或设置规则跟踪状态实体的列表。 + /// + public List Tracks { get; set; } + + /// + /// 获取或设置因素项模型的列表。 + /// + public List FactorItems { get; set; } + + /// + /// 获取或设置货物类型的列表。 + /// + public List CargoTypes { get; set; } + + /// + /// 获取或设置月份的列表。 + /// + public List Months { get; set; } + + /// + /// 获取或设置是否中转的列表。 + /// + public List IsTransit { get; set; } + + /// + /// 获取或设置区域的列表。 + /// + public List Areas { get; set; } + + /// + /// 获取或设置起运港口的列表。 + /// + public List DeparturePorts { get; set; } + + /// + /// 获取或设置产品编号的列表。 + /// + public List ProductCodes { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs new file mode 100644 index 00000000..554d1e2c --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public class RuleTrackStateModel +{ + /// + /// Gets or sets the start track value. + /// + public int Start { get; set; } + + /// + /// Gets or sets the end track value. + /// + public int End { get; set; } + + /// + /// Gets or sets the user to notify. + /// + public string NotifyUser { get; set; } + + /// + /// Gets or sets the notification template. + /// + public string NotifyTemplate { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate.cs new file mode 100644 index 00000000..353b4ebc --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Domain.Aggregates; + +public class KPIAreaAggregate +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs new file mode 100644 index 00000000..cc1d5168 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs @@ -0,0 +1,68 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; + +public interface IKpiAreaRepository:IBasicRepository +{ + /// + /// 创建分区 + /// + /// + /// + ValueTask CreateAreaAsync(RuleAreaEntity entity); + + /// + /// 添加分区信息 + /// + /// + /// + ValueTask AddAreaInfoAsync(RuleAreaInfoEntity entity); + + /// + /// 删除分区信息 + /// + /// 分区信息id + /// + Task DeleteAreaInfo(int areaInfoId); + + /// + /// 删除分区 + /// + /// 分区id + /// + ValueTask DeleteArea(int areaId); + + /// + /// 更新区域信息 + /// + /// + /// + Task UpdateAreaInfoAsync(RuleAreaInfoEntity entity); + + /// + /// 获得分区 + /// + /// + /// + Task> GetAreas(QueryAreaRequest query); + + /// + /// 获取分区信息 + /// + /// + /// + Task> GetAreaInfos(QueryAreaInfoRequest query); + + /// + /// 获取分区信息通过id + /// + /// + /// + Task GetAreaInfoById(int id); + + /// + /// 获取所有区域信息 + /// + /// + Task> GetAllAreaInfos(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs new file mode 100644 index 00000000..2f404cea --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs @@ -0,0 +1,50 @@ +namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; + +[SugarTable("t_rule_area", TableDescription = "KPI分区主表")] +public class RuleAreaEntity : IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")] + public int Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId", ColumnDescription = "子系统id")] + public int SubSystemId { get; set; } + + /// + /// 分区名称KPI名称 + /// + [SugarColumn(ColumnName = "Name", Length = 64, ColumnDescription = "分区名称KPI名称")] + public string Name { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", ColumnDescription = "创建人")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", ColumnDescription = "创建时间")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", ColumnDescription = "更新人")] + public int UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", ColumnDescription = "更新时间")] + public DateTime UpdateTime { get; set; } + + [SugarColumn(IsIgnore = true)] + public List AreaInfos { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs new file mode 100644 index 00000000..66b28382 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs @@ -0,0 +1,71 @@ +namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; + +[SugarTable("t_rule_area_info", TableDescription = "kpi 区域子表")] +public class RuleAreaInfoEntity : IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")] + public int Id { get; set; } + + /// + /// t_rule_area 表id + /// + [SugarColumn(ColumnName = "AreaId", ColumnDescription = "t_rule_area 表id")] + public int AreaId { get; set; } + + /// + /// 国家或地区 + /// + [SugarColumn(ColumnName = "Country", Length = 128, ColumnDescription = "国家或地区")] + public string Country { get; set; } + + /// + /// 州或者省份 + /// + [SugarColumn(ColumnName = "Province", Length = 128, IsNullable = true, ColumnDescription = "州或者省份")] + public string Province { get; set; } + + /// + /// 城市 + /// + [SugarColumn(ColumnName = "City", Length = 128, IsNullable = true, ColumnDescription = "城市")] + public string City { get; set; } + + /// + /// 起始邮编 + /// + [SugarColumn(ColumnName = "LeftPostcode", Length = 10, IsNullable = true, ColumnDescription = "起始邮编")] + public string LeftPostcode { get; set; } + + /// + /// 截止邮编 + /// + [SugarColumn(ColumnName = "RightPostcode", Length = 10, IsNullable = true, ColumnDescription = "截止邮编")] + public string RightPostcode { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", ColumnDescription = "创建人")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", ColumnDescription = "创建时间")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", IsNullable = false, ColumnDescription = "更新人")] + public int UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", IsNullable = false, ColumnDescription = "更新时间")] + public DateTime UpdateTime { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index e0f19389..9a7c4597 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -131,6 +131,24 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "LeavePort")] public string? LeavePort { get; set; } + + /// + /// 起运港口 + /// + [SugarColumn(ColumnName = "CargoType")] + public string? CargoType { get; set; } + + /// + /// 起运港口 + /// + [SugarColumn(ColumnName = "IsTransfer")] + public bool? IsTransfer { get; set; } + + /// + /// 起运港口 + /// + [SugarColumn(ColumnName = "ProductCode")] + public string? ProductCode { get; set; } [SugarColumn(IsIgnore = true)] public List OrderFlights { get; set; } [SugarColumn(IsIgnore = true)] public List OrderTemplates { get; set; } diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs index 3dd246c4..baf25867 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs @@ -11,4 +11,9 @@ public partial class GlobalConst /// 轨迹推送记录 es索引名称(模板) /// public const string TrackPushRecordsIndex = "sjzy_track_push_records"; + + /// + /// 预警规则 es索引名称(模板) + /// + public const string RuleFactorIndex = "sjzy_rule_factor"; } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index e2ca18ae..dcaf7a35 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -21,4 +21,19 @@ public partial class GlobalConst /// 轨迹拉取配置信息redis key前缀 /// public const string TrackPullContentKeyPrefix = "TrackPullContent"; + + /// + /// 规则因素缓存redis key前缀 + /// + public const string RuleFactorKeyPrefix = "RuleFactor"; + + /// + /// 预警通知redis key前缀 + /// + public const string ForewarningNotifyKeyPrefix = "ForewarningNotity"; + + /// + /// kpi区域redis key前缀 + /// + public const string KpiAreaKeyPrefix = "KpiArea"; } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs new file mode 100644 index 00000000..789dd29f --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class AddRuleAreaInfoRequest +{ + [Required] + public string Country { get; set; } + + public string? Province { get; set; } + + public string? City { get; set; } + + public string? LeftPostCode { get; set; } + + public string? RightPostCode { get; set; } + + [Required] + public int AreaId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs new file mode 100644 index 00000000..d0703d4a --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs @@ -0,0 +1,9 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class AreaDto +{ + public int Id { get; set; } + public int SubSystemId { get; set; } + public string Name { get; set; } + public DateTime UpdateTime { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs new file mode 100644 index 00000000..9ac65e86 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs @@ -0,0 +1,35 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleAreaInfoDto +{ + /// + /// 分区信息id + /// + public int Id { get; set; } + + /// + /// 分区id + /// + public int AreaId { get; set; } + + /// + /// 国家或地区 + /// + public string Country { get; set; } + + /// + /// 省份 + /// + public string Province { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 开始邮编 + /// + public string LeftPostcode { get; set; } + public string RightPostcode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs new file mode 100644 index 00000000..a3801625 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class CreateRuleAreaRequest +{ + /// + /// 系统id + /// + [Required] + public int SystemId { get; set; } + + /// + /// 名称 + /// + [Required] + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs new file mode 100644 index 00000000..68199b0f --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs @@ -0,0 +1,65 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning +{ + public class CreateRuleFactorRequest + { + /// + /// RuleId 表的id,小于0 表示创建新的规则 + /// + public int RuleId { get; set; } + + /// + /// 模板名称 + /// + public string Name { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomId { get; set; } + + /// + /// 获取或设置规则跟踪状态实体的列表。 + /// + public List Tracks { get; set; } + + /// + /// 获取或设置因素项模型的列表。 + /// + public List FactorItems { get; set; } + + /// + /// 获取或设置货物类型的列表。 + /// + public List CargoTypes { get; set; } + + /// + /// 获取或设置月份的列表。 + /// + public List Months { get; set; } + + /// + /// 获取或设置是否中转的列表。 + /// + public List IsTransit { get; set; } + + /// + /// 获取或设置区域的列表。 + /// + public List Areas { get; set; } + + /// + /// 获取或设置起运港口的列表。 + /// + public List DeparturePorts { get; set; } + + /// + /// 获取或设置产品编号的列表。 + /// + public List ProductCodes { get; set; } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs new file mode 100644 index 00000000..9360d491 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs @@ -0,0 +1,16 @@ +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class FactorItemDto +{ + /// + /// Gets or sets the sort order. + /// + public int Sort { get; set; } + + /// + /// Gets or sets the type of the rule factor. + /// + public RuleFactorType FactorType { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs new file mode 100644 index 00000000..c44d633f --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs @@ -0,0 +1,30 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class ForewarningOrderModel:IForewarningFactorValue +{ + /// + /// 订单id + /// + public int Id { get; set; } + + /// + /// 当前轨迹状态 + /// + public int Track { get; set; } + + public int SystemId { get; set; } + + public int CustomerId { get; set; } + + public string CargoType { get; set; } + + public int? Month { get; set; } + + public int? Area { get; set; } + + public bool? IsTransit { get; set; } + + public string DeparturePort { get; set; } + + public string ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs new file mode 100644 index 00000000..b8499e64 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs @@ -0,0 +1,26 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public record struct ForewarningRule:IForewarningFactorValue +{ + public int Id { get; set; } + + public int CustomerId { get; set; } + + public int SystemId { get; set; } + public int RuleId { get; set; } + public float Remind { get; set; } + public float Timeliness { get; set; } + public int Count { get; set; } + public int TrackStart { get; set; } + public int TrackEnd { get; set; } + public string CargoType { get; set; } + public int? Month { get; set; } + public int? Area { get; set; } + public bool? IsTransit { get; set; } + public string DeparturePort { get; set; } + public string ProductCode { get; set; } + + public string Conect { get; set; } + + public string Template { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs new file mode 100644 index 00000000..4ace20ac --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs @@ -0,0 +1,16 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public interface IForewarningFactorValue +{ + public string CargoType { get; set; } + + public int? Month { get; set; } + + public int? Area { get; set; } + + public bool? IsTransit { get; set; } + + public string DeparturePort { get; set; } + + public string ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs new file mode 100644 index 00000000..a9273783 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class KpiAreaInfo +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs new file mode 100644 index 00000000..8b023cac --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs @@ -0,0 +1,34 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class ModifyTimelinessRequest +{ + public List Items { get; set; } + + /// + /// 规则模板id + /// + public int RuleId { get; set; } +} + +public class TimelinessDto +{ + /// + /// 时效 + /// + public float Timeliness { get; set; } + + /// + /// 提醒时效 + /// + public float Remind { get; set; } + + /// + /// 提醒次数 + /// + public int Count { get; set; } + + /// + /// 规则id + /// + public int Id { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs new file mode 100644 index 00000000..196a65bf --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class QueryAreaInfoRequest: PageInfoInput +{ + public int AreaId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs new file mode 100644 index 00000000..31befffd --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class QueryAreaRequest:PageInfoInput +{ + /// + /// 分区名称 + /// + public string? Name { get; set; } + + /// + /// 子系统id + /// + public int? SystemId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs new file mode 100644 index 00000000..5bb9fea1 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class QueryForewarningRequest: PageInfoInput +{ + /// + /// 子系统id + /// + public int? SystemId { get; set; } + + /// + /// 客户或者模板名称 + /// + public string? KeyWord { get; set; } + + /// + /// 排序方式,不填不排序 + /// + public string? SortField { get; set; } + + /// + /// 排序方式 + /// + public bool IsAsc { get; set; } = false; +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs new file mode 100644 index 00000000..0014a95a --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class QueryForewarningRuleRequest: PageInfoInput +{ + /// + /// kpi 预警规则模板id + /// + public int RuleId { get; set; } + + /// + /// 排序方式,不填不排序 + /// + public string? SortField { get; set; } + + /// + /// 排序方式 + /// + public bool IsAsc { get; set; } = false; +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs new file mode 100644 index 00000000..4cce0e58 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs @@ -0,0 +1,22 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleCollectDto +{ + public int Id { get; set; } + public int RuleId { get; set; } + public float Remind { get; set; } + public float Timeliness { get; set; } + public int Count { get; set; } + public int TrackStart { get; set; } + public int TrackEnd { get; set; } + public string CargoType { get; set; } + public string Month { get; set; } + public int? Area { get; set; } + public bool? IsTransit { get; set; } + public string DeparturePort { get; set; } + public string ProductCode { get; set; } + public int CreateUserId { get; set; } + public DateTime CreateTime { get; set; } + public int UpdateUserId { get; set; } + public DateTime UpdateTime { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs new file mode 100644 index 00000000..b4b1fadd --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs @@ -0,0 +1,7 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleCollectRequest +{ + public string Name { get; set; } + +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleFactor.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleFactor.cs new file mode 100644 index 00000000..add12997 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleFactor.cs @@ -0,0 +1,37 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleFactor +{ + public int RuleId { get; set; } + + public int SystemId { get; set; } + + public int CustomerId { get; set; } + + /// + /// Gets or sets the start track value. + /// + public int Start { get; set; } + + /// + /// Gets or sets the end track value. + /// + public int End { get; set; } + + /// + /// Gets or sets the user to notify. + /// + public string NotifyUser { get; set; } + + /// + /// Gets or sets the notification template. + /// + public string NotifyTemplate { get; set; } + + /// + /// 获取或设置因素项模型的列表。 + /// + public List FactorItems { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs new file mode 100644 index 00000000..93644080 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs @@ -0,0 +1,42 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleInfoModel +{ + /// + /// 获取或设置因素项模型的列表。 + /// + public FactorItemModel FactorItems { get; set; } + + /// + /// 获取或设置货物类型的列表。 + /// + public string CargoTypes { get; set; } + + /// + /// 获取或设置月份的列表。 + /// + public short Months { get; set; } + + /// + /// 获取或设置是否中转的列表。 + /// + public bool? IsTransit { get; set; } + + /// + /// 获取或设置区域的列表。 + /// + public int Areas { get; set; } + + /// + /// 获取或设置起运港口的列表。 + /// + public string DeparturePorts { get; set; } + + /// + /// 获取或设置产品编号的列表。 + /// + public string ProductCodes { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs new file mode 100644 index 00000000..eda39cc7 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs @@ -0,0 +1,40 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleNotifyValue +{ + public int RuleId { get; set; } + + public int OrderId { get; set; } + + /// + /// 第几次通知 + /// + public int Count { get; set; } + + /// + /// 结束轨迹状态 + /// + public int TrackEnd { get; set; } + + public RuleNotifyValue(int ruleId, int orderId, int count, int trackEnd) + { + RuleId = ruleId; + OrderId = orderId; + Count = count; + TrackEnd = trackEnd; + } + + public RuleNotifyValue(string notifyValue) + { + var values = notifyValue.Split(':'); + RuleId = int.Parse(values[0]); + OrderId = int.Parse(values[1]); + Count = int.Parse(values[2]); + TrackEnd = int.Parse(values[3]); + } + + public override string ToString() + { + return $"{RuleId}:{OrderId}:{Count}:{TrackEnd}"; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs new file mode 100644 index 00000000..52abd1fa --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleTrackStateDto +{ + /// + /// Gets or sets the start track value. + /// + public int Start { get; set; } + + /// + /// Gets or sets the end track value. + /// + public int End { get; set; } + + /// + /// Gets or sets the user to notify. + /// + public string NotifyUser { get; set; } + + /// + /// Gets or sets the notification template. + /// + public string NotifyTemplate { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs new file mode 100644 index 00000000..c6f52158 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class UpdateRuleAreaInfoRequest +{ + /// + /// 分区信息id + /// + public int Id { get; set; } + + [Required] + public string Country { get; set; } + + public string? Province { get; set; } + + public string? City { get; set; } + + public string? LeftPostCode { get; set; } + + public string? RightPostCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs new file mode 100644 index 00000000..f0bac318 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class UpdateRuleAreaRequest +{ + /// + /// 名称 + /// + [Required] + public string Name { get; set; } + + /// + /// 分区id + /// + public int Id { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Enums/RuleFactorType.cs b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs new file mode 100644 index 00000000..64d32839 --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs @@ -0,0 +1,38 @@ +namespace SJZY.Track.Domain.Enums; + + +/// +/// 枚举表示不同类型的规则因素。 +/// +public enum RuleFactorType +{ + /// + /// 表示货物类型。 + /// + CargoType, + + /// + /// 表示月份。 + /// + Month, + + /// + /// 表示分区或区域。 + /// + Areas, + + /// + /// 指示货物是否中转。 + /// + IsTransit, + + /// + /// 表示起运港口。 + /// + DeparturePort, + + /// + /// 表示产品编号。 + /// + ProductCode +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj b/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj index d086d460..ea3705c5 100644 --- a/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj +++ b/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj @@ -11,5 +11,10 @@ + + + + + diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs new file mode 100644 index 00000000..de1e628d --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Repository.Repositories; + +public class KpiAreaInfoRepository +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs new file mode 100644 index 00000000..601821e5 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -0,0 +1,103 @@ +using SJZY.Track.Domain; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Repository.Repositories; + +public class KpiAreaRepository:BasicRepository ,IKpiAreaRepository,ITransientDependency +{ + public async ValueTask CreateAreaAsync(RuleAreaEntity entity) + { + return await InsertReturnIdentityAsync(entity); + } + + public async ValueTask AddAreaInfoAsync(RuleAreaInfoEntity entity) + { + return await Context.Insertable(entity).ExecuteReturnIdentityAsync(); + } + + public async ValueTask DeleteArea(int areaId) + { + using var transaction = TransactionHelper.GetReadCommitted(); + await DeleteByIdAsync(areaId); + await Context.Deleteable().Where(x => x.AreaId == areaId).ExecuteCommandAsync(); + transaction.Complete(); + } + + public Task DeleteAreaInfo(int areaInfoId) + { + return Context.Deleteable().Where(val=>val.Id==areaInfoId).ExecuteCommandAsync(); + } + + public Task UpdateAreaInfoAsync(RuleAreaInfoEntity entity) + { + return Context.Updateable(entity).ExecuteCommandAsync(); + } + + /// + /// 获取分区 + /// + /// + /// + public async Task> GetAreas(QueryAreaRequest query) + { + var queryable = Context.Queryable(); + if (!string.IsNullOrEmpty(query.Name)) + { + queryable = queryable.Where(x => x.Name.Contains(query.Name)); + } + + if (query.SystemId.HasValue) + { + queryable = queryable.Where(x => x.SubSystemId == query.SystemId.Value); + } + + return await queryable.OrderBy(x => x.Id, OrderByType.Desc) + .Select(val=>new AreaDto() + { + Id = val.Id, + Name = val.Name, + SubSystemId = val.SubSystemId, + UpdateTime = val.CreateTime + }) + .ToPagedListAsync(query.PageIndex, query.PageSize); + } + + /// + /// 获得分区信息 + /// + /// + /// + public async Task> GetAreaInfos(QueryAreaInfoRequest query) + { + var queryable = Context.Queryable(); + queryable = queryable.Where(x => x.AreaId == query.AreaId); + return await queryable.OrderBy(x => x.Id, OrderByType.Desc) + .Select(val=>new RuleAreaInfoDto() + { + Id = val.Id, + AreaId = val.AreaId, + City = val.City, + Country = val.Country, + LeftPostcode = val.LeftPostcode, + RightPostcode = val.RightPostcode, + Province = val.Province + }) + .ToPagedListAsync(query.PageIndex, query.PageSize); + } + + public Task GetAreaInfoById(int id) + { + return Context.Queryable().FirstAsync(val => val.Id == id); + } + + /// + /// 获取所有区域信息 + /// + /// + public Task> GetAllAreaInfos() + { + return Context.Queryable().ToListAsync(); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs new file mode 100644 index 00000000..250eedf1 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs @@ -0,0 +1,50 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Repository.Repositories; + +public class RuleCollectRepository: BasicRepository, IRuleCollectRepository,ITransientDependency +{ + /// + /// 查询预警规则分页信息 + /// + /// + /// + public Task> QueryForewarningRule(QueryForewarningRuleRequest input) + { + var query = Context.Queryable() + .Where(val => val.RuleId == input.RuleId); + + if (!string.IsNullOrEmpty(input.SortField)) + { + query = query.OrderByPropertyName(input.SortField, input.IsAsc ? OrderByType.Asc : OrderByType.Desc); + } + + return query.Select(val=>MapToDto(val)) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + + private RuleCollectDto MapToDto(RuleCollectEntity entity) + { + return new RuleCollectDto() + { + Id = entity.Id, + RuleId = entity.RuleId, + Remind = entity.Remind, + Timeliness = entity.Timeliness, + Count = entity.Count, + TrackStart = entity.TrackStart, + TrackEnd = entity.TrackEnd, + CargoType = entity.CargoType, + Month = entity.Month, + Area = entity.Area, + IsTransit = entity.IsTransit, + DeparturePort = entity.DeparturePort, + ProductCode = entity.ProductCode, + CreateUserId = entity.CreateUserId, + CreateTime = entity.CreateTime, + UpdateUserId = entity.UpdateUserId, + UpdateTime = entity.UpdateTime + }; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs new file mode 100644 index 00000000..b9492f28 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs @@ -0,0 +1,53 @@ +using Nest; +using SJZY.Expand.ElasticSearch.Services; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +namespace SJZY.Track.Repository.Repositories; + +public class RuleFactorRepository:ElasticSearchContextAbstract, IRuleFactorRepository, + ITransientDependency +{ + public RuleFactorRepository(ConnectionFactory connectionFactory) : base(connectionFactory) + { + } + + public async Task CreateAsync(RuleFactorEntity entity) + { + await IndexDocumentAsync(entity); + } + + public async Task> GetFactorByIdsAsync(int[] ruleIds) + { + var response = await Context.SearchAsync(s => s.Query(q => q.Terms(t => t.Field(f => f.RuleId).Terms(ruleIds)))); + int num = response.ApiCall.HttpStatusCode ?? throw new Exception("数据查询失败,原因:" + response.DebugInformation); + switch (num) + { + case 200: + return response.Documents.ToList(); + case 404: + return new List(); + default: + throw new Exception($"数据查询失败,http status: {num},原因:{response.DebugInformation}"); + } + } + + /// + /// 获取所有数据 + /// + /// + /// + public async Task> GetAllList() + { + var response = await Context.SearchAsync(); + int num = response.ApiCall.HttpStatusCode ?? throw new Exception("数据查询失败,原因:" + response.DebugInformation); + switch (num) + { + case 200: + return response.Documents.ToList(); + case 404: + return new List(); + default: + throw new Exception($"数据查询失败,http status: {num},原因:{response.DebugInformation}"); + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/RuleRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleRepository.cs new file mode 100644 index 00000000..4867ab3f --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/RuleRepository.cs @@ -0,0 +1,53 @@ +using SJZY.Track.Domain; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Repository.Repositories; + +public class RuleRepository:BasicRepository ,IRuleRepository,ITransientDependency +{ + public async Task CreateForewarning(RuleEntity rule, RuleCollectEntity[] factorList) + { + using var tran = TransactionHelper.GetReadCommitted(); + + var ruleId = await InsertReturnIdentityAsync(rule); + foreach (var item in factorList) + { + item.RuleId = ruleId; + } + await Context.Insertable(factorList).ExecuteCommandAsync(); + tran.Complete(); + return ruleId; + } + + public async Task UpdateForewarning(RuleEntity rule,RuleCollectEntity[] factorList) + { + using var tran = TransactionHelper.GetReadCommitted(); + await UpdateAsync(rule); + await Context.Deleteable().Where(x=>x.RuleId==rule.Id).ExecuteCommandAsync(); + await Context.Insertable(factorList).ExecuteCommandAsync(); + tran.Complete(); + } + + /// + /// 查询预警模板分页信息 + /// + /// + /// + public Task> QueryForewarning(QueryForewarningRequest input) + { + var query = Context.Queryable() + .WhereIF(input.SystemId.HasValue,val=>val.SubSystemId == input.SystemId) + .WhereIF(string.IsNullOrEmpty(input.KeyWord), val=> val.CustomName.Contains(input.KeyWord)||val.Name.Contains(input.KeyWord)); + + if (!string.IsNullOrEmpty(input.SortField)) + { + query = query.OrderByPropertyName(input.SortField, input.IsAsc ? OrderByType.Asc : OrderByType.Desc); + } + + return query.ToPagedListAsync(input.PageIndex, input.PageSize); + } + + + +} \ No newline at end of file From c772c68e4784ec6f5214c3de65d7a8de0cc16dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Wed, 24 Jul 2024 11:14:58 +0800 Subject: [PATCH 17/60] review --- .../Helpers/ForewarningFactorHelper.cs | 42 +-- .../ForewarningNotifyService.cs | 98 +++--- .../ForewarningServices/ForewarningService.cs | 100 +++--- .../ForewarningServices/KpiAreaService.cs | 54 ++- .../RuleFactorCacheService.cs | 327 +++++++++--------- ...ctRepository.cs => IRuleItemRepository.cs} | 4 +- .../ForewarningAggregate/IRuleRepository.cs | 10 +- .../ForewarningAggregate/RuleFactorEntity.cs | 6 +- ...RuleCollectEntity.cs => RuleItemEntity.cs} | 17 +- .../KPIAreaAggregate/IKpiAreaRepository.cs | 6 +- .../Repositories/KpiAreaRepository.cs | 25 +- ...ectRepository.cs => RuleItemRepository.cs} | 14 +- .../Repositories/RuleRepository.cs | 27 +- 13 files changed, 361 insertions(+), 369 deletions(-) rename src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/{IRuleCollectRepository.cs => IRuleItemRepository.cs} (71%) rename src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/{RuleCollectEntity.cs => RuleItemEntity.cs} (92%) rename src/SJZY.Track.Repository/Repositories/{RuleCollectRepository.cs => RuleItemRepository.cs} (80%) diff --git a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs index c88ec276..5490aea1 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs @@ -5,54 +5,56 @@ namespace SJZY.Track.Application.Helpers; public class ForewarningFactorHelper { - public static RuleCollectEntity[] GetFactorItem([NotNull]RuleFactorEntity ruleFactors) + public static RuleItemEntity[] GetFactorItem([NotNull] RuleFactorEntity ruleFactors) { var total = Factorial(ruleFactors); - var ruleCollect = AllocateFactor(total,ruleFactors.RuleId); - Assignment(ruleCollect,total,ruleFactors.CargoTypes,(item,value)=>item.CargoType=value); - Assignment(ruleCollect,total,ruleFactors.Months,(item,value)=>item.Month=value); - Assignment(ruleCollect,total,ruleFactors.Areas,(item,value)=>item.Area=value); - Assignment(ruleCollect,total,ruleFactors.IsTransit,(item,value)=>item.IsTransit=value); - Assignment(ruleCollect,total,ruleFactors.DeparturePorts,(item,value)=>item.DeparturePort=value); - Assignment(ruleCollect,total,ruleFactors.ProductCodes,(item,value)=>item.ProductCode=value); + var ruleCollect = AllocateFactor(total, ruleFactors.RuleId); + Assignment(ruleCollect, total, ruleFactors.CargoTypes, (item, value) => item.CargoType = value); + Assignment(ruleCollect, total, ruleFactors.Months, (item, value) => item.Month = value); + Assignment(ruleCollect, total, ruleFactors.Areas, (item, value) => item.Area = value); + Assignment(ruleCollect, total, ruleFactors.IsTransit, (item, value) => item.IsTransit = value); + Assignment(ruleCollect, total, ruleFactors.DeparturePorts, (item, value) => item.DeparturePort = value); + Assignment(ruleCollect, total, ruleFactors.ProductCodes, (item, value) => item.ProductCode = value); return ruleCollect.ToArray(); } - - private static void Assignment(Span ruleCollect,int total,IReadOnlyList values,Action action) + + private static void Assignment(Span ruleCollect, int total, IReadOnlyList values, + Action action) { if (values.Count == 0) { return; } - + var segment = total / values.Count; - for(int index=0;index AllocateFactor(int total,int ruleId) + + private static Span AllocateFactor(int total, int ruleId) { - - Span factors = new RuleCollectEntity[total]; + Span factors = new RuleItemEntity[total]; for (int index = 0; index < total; index++) { - factors[index] = new RuleCollectEntity() + factors[index] = new RuleItemEntity() { RuleId = ruleId }; } + return factors; } - + internal static int Factorial(RuleFactorEntity ruleFactors) { - return ruleFactors.CargoTypes.Count*ruleFactors.Months.Count*ruleFactors.Areas.Count*ruleFactors.IsTransit.Count*ruleFactors.DeparturePorts.Count*ruleFactors.ProductCodes.Count; + return ruleFactors.CargoTypes.Count * ruleFactors.Months.Count * ruleFactors.Areas.Count * + ruleFactors.IsTransit.Count * ruleFactors.DeparturePorts.Count * ruleFactors.ProductCodes.Count; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index d692dad5..490c7c20 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -1,24 +1,22 @@ using FreeRedis; -using NetTaste; using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.Enums; -using SqlSugar; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; /// -/// 单例服务,用于处理预警通知 +/// 用于处理预警通知 /// -public class ForewarningNotifyService:IForewarningNotifyService,ITransientDependency +public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency { private IRuleFactorCacheService _ruleFactorCache; - IReadOnlyDictionary> _ruleGroupDict; - IReadOnlyDictionary> _factorDict; + IReadOnlyDictionary> _ruleGroupDict; + IReadOnlyDictionary> _factorDict; private IReadOnlyDictionary _rules; readonly INotifyService _notifyService; @@ -27,7 +25,7 @@ public class ForewarningNotifyService:IForewarningNotifyService,ITransientDepend _ruleFactorCache = ruleFactorCache; _notifyService = notifyService; } - + /// /// 创建预警通知 /// @@ -38,10 +36,10 @@ public class ForewarningNotifyService:IForewarningNotifyService,ITransientDepend var rules = GetRule(order); if (rules == null || rules.Count == 0) return 0; - - return await ExecuteRule(rules,order.Id); + + return await ExecuteRule(rules, order.Id); } - + /// /// 清除预警通知 /// @@ -56,10 +54,10 @@ public class ForewarningNotifyService:IForewarningNotifyService,ITransientDepend var willDeleteMembers = new List(); foreach (var rule in rules) { - var allRuleNotities= DeleteNotifyValue(rule, order.Id); + var allRuleNotities = DeleteNotifyValue(rule, order.Id); willDeleteMembers.AddRange(allRuleNotities); } - + await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKeyPrefix, willDeleteMembers.ToArray()); return willDeleteMembers.Count; } @@ -67,32 +65,33 @@ public class ForewarningNotifyService:IForewarningNotifyService,ITransientDepend public void SendNotification(int intervalMinute) { var currentTimestamp = GetTimestamp(DateTime.Now); - var notifyMembers = RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKeyPrefix, 0, currentTimestamp); + var notifyMembers = + RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKeyPrefix, 0, currentTimestamp); if (notifyMembers == null || notifyMembers.Length == 0) return; - + var notifyValues = notifyMembers.Select(val => new RuleNotifyValue(val)); foreach (var notifyValue in notifyValues) { - if(!_rules.TryGetValue(notifyValue.RuleId, out var rule)) + if (!_rules.TryGetValue(notifyValue.RuleId, out var rule)) continue; //todo 发送通知 _notifyService.SendNotification(""); } } - + public void ClearCache() { _ruleGroupDict = null; _factorDict = null; _rules = null; } - - private List DeleteNotifyValue(ForewarningRule rule,int orderId) + + private List DeleteNotifyValue(ForewarningRule rule, int orderId) { var members = new List(); - for(var index=0;index /// 获取规则 /// @@ -112,45 +111,45 @@ public class ForewarningNotifyService:IForewarningNotifyService,ITransientDepend { return null; } - + var keys = GetForewarningKeys(factors, order); - var result = new List< ForewarningRule>(); - + var result = new List(); + foreach (var item in keys) { if (!_ruleGroupDict.TryGetValue(item, out var rules)) continue; - - var allRules = rules.Where(val=>val.TrackStart <= order.Track && val.TrackEnd >= order.Track); + + var allRules = rules.Where(val => val.TrackStart <= order.Track && val.TrackEnd >= order.Track); result.AddRange(allRules); } return result; } - private async ValueTask ExecuteRule(List rules,int orderId) + private async ValueTask ExecuteRule(List rules, int orderId) { var members = new List(); foreach (var rule in rules) { - var notifys = ExecuteRule(rule,orderId); + var notifys = ExecuteRule(rule, orderId); members.AddRange(notifys); } await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKeyPrefix, members.ToArray()); return members.Count; } - - private List ExecuteRule(ForewarningRule rule,int orderId) + + private List ExecuteRule(ForewarningRule rule, int orderId) { var members = new List(); - var intervalMinute = 60 * ((rule.Timeliness - rule.Remind) / rule.Count);// 间隔多少分钟 - - for(var index=0;index GetForewarningKeys(List factors, IForewarningFactorValue rule) { var keys = new List(); @@ -179,34 +178,35 @@ public class ForewarningNotifyService:IForewarningNotifyService,ITransientDepend return keys; } - + private async Task Init() { + // todo:缓存设计有问题 重构 120s 10w 30w 3000k/s var allFactorCollect = await _ruleFactorCache.GetAllFactorCollect(); var factors = await _ruleFactorCache.GetAllRuleFactor(); - var factorsMap = factors.GroupBy(val=>val.RuleId) - .ToDictionary(val=>val.Key,val=>val.First()); - + var factorsMap = factors.GroupBy(val => val.RuleId) + .ToDictionary(val => val.Key, val => val.First()); + _rules = allFactorCollect.ToDictionary(val => val.Id); - - _factorDict = factors.GroupBy(val => GetFactorKey(val.CustomerId,val.SystemId)) - .ToDictionary(val=>val.Key,val=>val.ToList()); + + _factorDict = factors.GroupBy(val => GetFactorKey(val.CustomerId, val.SystemId)) + .ToDictionary(val => val.Key, val => val.ToList()); _ruleGroupDict = allFactorCollect.GroupBy(x => GetRuleKey(x, factorsMap[x.RuleId])) .ToDictionary(val => val.Key, val => val.ToList()); } - - private string GetFactorKey(int customerId,int systemId) + + private string GetFactorKey(int customerId, int systemId) { return $"{customerId}:{systemId}"; } - - private string GetRuleKey(IForewarningFactorValue rule,RuleFactor factors) + + private string GetRuleKey(IForewarningFactorValue rule, RuleFactor factors) { var key = ""; foreach (var factorItem in factors.FactorItems) { - key+=GetFactorValue(factorItem,rule); + key += GetFactorValue(factorItem, rule); } return key; diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index 2f660c83..b9544324 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -1,29 +1,26 @@ -using System.Diagnostics.CodeAnalysis; -using AutoMapper; using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Dtos.Forewarning; -using SqlSugar; namespace SJZY.Track.Application.Services.ForewarningServices; [ApiExplorerSettings(GroupName = "预警服务")] [Route("/ForewarningService")] -public class ForewarningService: ApplicationService +public class ForewarningService : ApplicationService { readonly IRuleRepository _ruleRepository; IRuleFactorRepository _ruleFactorRepository; - private IRuleCollectRepository _ruleCollectRepository; - + private IRuleItemRepository _ruleItemRepository; + public ForewarningService(IRuleRepository ruleRepository - ,IRuleFactorRepository ruleFactorRepository - , IRuleCollectRepository ruleCollectRepository) + , IRuleFactorRepository ruleFactorRepository + , IRuleItemRepository ruleItemRepository) { _ruleRepository = ruleRepository; _ruleFactorRepository = ruleFactorRepository; - _ruleCollectRepository = ruleCollectRepository; + _ruleItemRepository = ruleItemRepository; } - + /// /// 创建预警模板,存在则更新 /// @@ -32,46 +29,48 @@ public class ForewarningService: ApplicationService [HttpPost("ModifyForewarning")] public async ValueTask ModifyForewarning(CreateRuleFactorRequest input) { - var factors = ObjectMapper.Map(input); - var ruleCollects = ForewarningFactorHelper.GetFactorItem(factors); - + var factors = ObjectMapper.Map(input); + var ruleItems = ForewarningFactorHelper.GetFactorItem(factors); + //todo 原子性没有保证,后续可能需要调整 if (input.RuleId > 0) { await _ruleFactorRepository.DeleteByIdAsync(input.RuleId.ToString()); } - + if (input.RuleId > 0) { - var ruleTemplate = await _ruleRepository.GetFirstAsync(val=>val.Id == input.RuleId); + var ruleTemplate = await _ruleRepository.GetFirstAsync(val => val.Id == input.RuleId); if (ruleTemplate == null) - return new UnifyResultDto(false,"规则不存在"); - + return new UnifyResultDto(false, "规则不存在"); + ruleTemplate.Name = input.Name; ruleTemplate.CustomId = input.CustomId; await _ruleFactorRepository.IndexDocumentAsync(factors); - await _ruleRepository.UpdateForewarning(ruleTemplate, ruleCollects); - return new UnifyResultDto(true,"保存成功"); + await _ruleRepository.UpdateForewarning(ruleTemplate, ruleItems); + return new UnifyResultDto(true, "保存成功"); } - + var newRuleTemplate = ObjectMapper.Map(input); - var ruleTemplateId = await _ruleRepository.CreateForewarning(newRuleTemplate, ruleCollects); - factors.Id = ruleTemplateId.ToString(); - return new UnifyResultDto(true,"保存成功"); + var ruleId = await _ruleRepository.CreateForewarning(newRuleTemplate, ruleItems); + factors.Id = ruleId.ToString(); + await _ruleFactorRepository.IndexDocumentAsync(factors); + return new UnifyResultDto(true, "保存成功"); } - + /// /// 修改时效 /// [HttpPost("ModifyTimeliness")] public async ValueTask ModifyTimeliness(ModifyTimelinessRequest input) { - var ruleIds = input.Items.Select(val=>val.Id).ToList(); - var ruleCollect = await _ruleCollectRepository.GetListAsync(val => ruleIds.Contains(val.Id) && val.RuleId == input.RuleId); - if (ruleCollect == null|| ruleCollect.Count == 0) - throw new BusinessException(message:"规则不存在"); - + var ruleIds = input.Items.Select(val => val.Id).ToList(); + var ruleCollect = + await _ruleItemRepository.GetListAsync(val => ruleIds.Contains(val.Id) && val.RuleId == input.RuleId); + if (ruleCollect == null || ruleCollect.Count == 0) + throw new BusinessException(message: "规则不存在"); + var ruleMaps = ruleCollect.ToDictionary(val => val.Id); var notModifyList = new List(); foreach (var item in input.Items) @@ -81,48 +80,45 @@ public class ForewarningService: ApplicationService notModifyList.Add(item.Id); continue; } - - rule.Remind= item.Remind; + + rule.Remind = item.Remind; rule.Timeliness = item.Timeliness; rule.Count = item.Count; } - - await _ruleCollectRepository.UpdateRangeAsync(ruleCollect,val=>val.RuleId==input.RuleId); - + + await _ruleItemRepository.UpdateRangeAsync(ruleCollect, val => val.RuleId == input.RuleId); + if (notModifyList.Count > 0) return new UnifyResultDto(true, $"更新成功,规则{string.Join(",", notModifyList)}不存在"); - + return new UnifyResultDto(true, "更新成功"); } - - /// - /// 查询预警模板列表 - /// - /// - [HttpPost("QueryForewarning")] - public async Task QueryForewarning(QueryForewarningRequest input) - { - var result = await _ruleRepository.QueryForewarning(input); - return new UnifyResultDto(true, result); - } /// /// 查询预警规则列表 /// - [HttpPost("QueryForewarningRules")] - public async Task QueryForewarningRules(QueryForewarningRuleRequest input) + /// + [HttpPost("QueryForewarning")] + public async Task QueryForewarning(QueryForewarningRequest input) { - var result = await _ruleCollectRepository.QueryForewarningRule(input); + var result = await _ruleRepository.QueryForewarningRuleAsync(input); return new UnifyResultDto(true, result); } - + + /// + /// 查询预警规则明细列表 + /// + [HttpPost("QueryForewarningRules")] + public async Task> QueryForewarningRuleItems(QueryForewarningRuleRequest input) + { + return await _ruleItemRepository.QueryForewarningRuleItemsAsync(input); + } + /// /// 发送预警通知 /// [HttpPost("SendForewarningNotification")] public void SendForewarningNotification() { - } - } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs index f87b3109..3fc7c3ac 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -1,7 +1,5 @@ -using AutoMapper; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; -using SqlSugar; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -9,9 +7,9 @@ namespace SJZY.Track.Application.Services.ForewarningServices; [Route("/ForewarningService")] public class KpiAreaService : ApplicationService { - readonly IKpiAreaRepository _ruleAreaRepository; + private readonly IKpiAreaRepository _ruleAreaRepository; - public KpiAreaService(IKpiAreaRepository ruleAreaRepository ) + public KpiAreaService(IKpiAreaRepository ruleAreaRepository) { _ruleAreaRepository = ruleAreaRepository; } @@ -26,7 +24,7 @@ public class KpiAreaService : ApplicationService { var ruleAreaEntity = ObjectMapper.Map(input); var areaId = await _ruleAreaRepository.CreateAreaAsync(ruleAreaEntity); - return new UnifyResultDto(true,areaId, "创建成功"); + return new UnifyResultDto(true, areaId, "创建成功"); } /// @@ -39,7 +37,7 @@ public class KpiAreaService : ApplicationService { var ruleAreaEntity = ObjectMapper.Map(input); var ruleInfoId = await _ruleAreaRepository.AddAreaInfoAsync(ruleAreaEntity); - return new UnifyResultDto(true,ruleInfoId, "添加成功"); + return new UnifyResultDto(true, ruleInfoId, "添加成功"); } /// @@ -53,7 +51,7 @@ public class KpiAreaService : ApplicationService await _ruleAreaRepository.DeleteArea(id); return new UnifyResultDto(true, "删除成功"); } - + /// /// 删除分区信息 /// @@ -65,7 +63,7 @@ public class KpiAreaService : ApplicationService await _ruleAreaRepository.DeleteAreaInfo(id); return new UnifyResultDto(true, "删除成功"); } - + /// /// 更新区域信息 /// @@ -74,18 +72,18 @@ public class KpiAreaService : ApplicationService [HttpPost("KpiArea/ModifyKpiArea")] public async Task ModifyKpiArea(UpdateRuleAreaRequest input) { - if(input.Id<=0) - return new UnifyResultDto(false,"id不能为空"); - - var ruleArea =await _ruleAreaRepository.GetFirstAsync(val=>val.Id==input.Id); - if(ruleArea==null) - return new UnifyResultDto(false,"未找到该区域"); - + if (input.Id <= 0) + return new UnifyResultDto(false, "id不能为空"); + + var ruleArea = await _ruleAreaRepository.GetFirstAsync(val => val.Id == input.Id); + if (ruleArea == null) + return new UnifyResultDto(false, "未找到该区域"); + ruleArea.Name = input.Name; await _ruleAreaRepository.UpdateAsync(ruleArea); - return new UnifyResultDto(true,"更新成功"); + return new UnifyResultDto(true, "更新成功"); } - + /// /// 更新区域信息 /// @@ -94,19 +92,19 @@ public class KpiAreaService : ApplicationService [HttpPost("KpiArea/ModifyKpiAreaInfo")] public async Task ModifyKpiAreaInfo(UpdateRuleAreaInfoRequest input) { - if(input.Id<=0) - return new UnifyResultDto(false,"id不能为空"); - + if (input.Id <= 0) + return new UnifyResultDto(false, "id不能为空"); + //todo 测试不存在id的情况 - RuleAreaInfoEntity areaInfo = await _ruleAreaRepository.GetAreaInfoById(input.Id); - if(areaInfo==null) - return new UnifyResultDto(false,"未找到该区域信息"); - - var ruleAreaEntity = ObjectMapper.Map(input,areaInfo); + var areaInfo = await _ruleAreaRepository.GetAreaInfoById(input.Id); + if (areaInfo == null) + return new UnifyResultDto(false, "未找到该区域信息"); + + var ruleAreaEntity = ObjectMapper.Map(input, areaInfo); await _ruleAreaRepository.UpdateAreaInfoAsync(ruleAreaEntity); - return new UnifyResultDto(true,"更新成功"); + return new UnifyResultDto(true, "更新成功"); } - + /// /// 查询分区列表 /// @@ -117,7 +115,7 @@ public class KpiAreaService : ApplicationService { return await _ruleAreaRepository.GetAreas(input); } - + /// /// 查询分区列表 /// diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs index 6b7ffcb4..74bc9345 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs @@ -7,189 +7,188 @@ using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; -public class RuleFactorCacheService:IRuleFactorCacheService,ITransientDependency +public class RuleFactorCacheService : IRuleFactorCacheService, ITransientDependency { - private const string GlobalFactorLockKey = "RuleFactorCacheService_GlobalLock"; - private const string GlobalRuleLockKey = "RuleFactorCacheService_GlobalLock"; - readonly IRuleFactorRepository _ruleFactorRepository; - readonly IRuleCollectRepository _ruleCollectRepository; - readonly IRuleRepository _ruleRepository; + private const string GlobalFactorLockKey = "RuleFactorCacheService_GlobalLock"; + private const string GlobalRuleLockKey = "RuleFactorCacheService_GlobalLock"; + readonly IRuleFactorRepository _ruleFactorRepository; + readonly IRuleItemRepository _ruleItemRepository; + readonly IRuleRepository _ruleRepository; - public RuleFactorCacheService(IRuleFactorRepository ruleFactorRepository, - IRuleCollectRepository ruleCollectRepository, IRuleRepository ruleRepository) - { - _ruleFactorRepository = ruleFactorRepository; - _ruleCollectRepository = ruleCollectRepository; - _ruleRepository = ruleRepository; - } + public RuleFactorCacheService(IRuleFactorRepository ruleFactorRepository, + IRuleItemRepository ruleItemRepository, IRuleRepository ruleRepository) + { + _ruleFactorRepository = ruleFactorRepository; + _ruleItemRepository = ruleItemRepository; + _ruleRepository = ruleRepository; + } - private string GetKey() - { - return $"{GlobalConst.RuleFactorKeyPrefix}:allFactor"; - } - - private string GetRuleKey() - { - return $"{GlobalConst.RuleFactorKeyPrefix}:allRule"; - } + private string GetKey() + { + return $"{GlobalConst.RuleFactorKeyPrefix}:allFactor"; + } - /// - /// 获取所有规则数据 - /// - /// - [NonAction] - public async Task GetAllFactorCollect() - { - - var key = GetRuleKey(); - var result =await RedisHelper.Client.GetAsync(key); - if (result == null) - { - using (var globalLock = RedisHelper.Client.Lock(GlobalRuleLockKey, 10)) - { - result =await RedisHelper.Client.GetAsync(key); - if (result != null) return result; + private string GetRuleKey() + { + return $"{GlobalConst.RuleFactorKeyPrefix}:allRule"; + } - var ruleCollect = await _ruleCollectRepository.GetListAsync(val => true); - if (ruleCollect == null || ruleCollect.Count == 0) + /// + /// 获取所有规则数据 + /// + /// + [NonAction] + public async Task GetAllFactorCollect() + { + var key = GetRuleKey(); + var result = await RedisHelper.Client.GetAsync(key); + if (result == null) + { + using (var globalLock = RedisHelper.Client.Lock(GlobalRuleLockKey, 10)) { - ForewarningRule[] rules = new ForewarningRule[0]; - await RedisHelper.Client.SetAsync(key,rules , TimeSpan.FromSeconds(20)); - return result; + result = await RedisHelper.Client.GetAsync(key); + if (result != null) return result; + + var ruleCollect = await _ruleItemRepository.GetListAsync(val => true); + if (ruleCollect == null || ruleCollect.Count == 0) + { + ForewarningRule[] rules = new ForewarningRule[0]; + await RedisHelper.Client.SetAsync(key, rules, TimeSpan.FromSeconds(20)); + return result; + } + + var ruleList = ruleCollect.SelectMany(RuleEntityToRule); + await RedisHelper.Client.SetAsync(key, ruleList); + return result; } + } - var ruleList = ruleCollect.SelectMany(RuleEntityToRule); - await RedisHelper.Client.SetAsync(key, ruleList); - return result; - } - } + return result; + } - return result; - } - - /// - /// 获取所有因素数据 - /// - /// 获取所有因素,返回值可能为空 - [NonAction] - public async Task> GetAllRuleFactor() - { - var key = GetKey(); - var result =await RedisHelper.Client.GetAsync>(key); - if (result == null) - { - using (var globalLock = RedisHelper.Client.Lock(GlobalFactorLockKey, 10)) - { - result =await RedisHelper.Client.GetAsync>(key); - if (result != null) return result; - - result = await GenerateAllRuleFactor(); - if (result == null || result.Count == 0) + /// + /// 获取所有因素数据 + /// + /// 获取所有因素,返回值可能为空 + [NonAction] + public async Task> GetAllRuleFactor() + { + var key = GetKey(); + var result = await RedisHelper.Client.GetAsync>(key); + if (result == null) + { + using (var globalLock = RedisHelper.Client.Lock(GlobalFactorLockKey, 10)) { - await RedisHelper.Client.SetAsync(key,new List() , TimeSpan.FromSeconds(20)); - return result; + result = await RedisHelper.Client.GetAsync>(key); + if (result != null) return result; + + result = await GenerateAllRuleFactor(); + if (result == null || result.Count == 0) + { + await RedisHelper.Client.SetAsync(key, new List(), TimeSpan.FromSeconds(20)); + return result; + } + + await RedisHelper.Client.SetAsync(key, result); + return result; } - - await RedisHelper.Client.SetAsync(key, result); - return result; - } - } + } - return result; - } - - [NonAction] - public void ClearFactorCache() - { - RedisHelper.Client.DelAsync(GetKey()); - } + return result; + } - [NonAction] - public void ClearRuleCache() - { - RedisHelper.Client.DelAsync(GetRuleKey()); - } + [NonAction] + public void ClearFactorCache() + { + RedisHelper.Client.DelAsync(GetKey()); + } - private async Task> GenerateAllRuleFactor() - { - var factors =await _ruleFactorRepository.GetAllList(); - var ruleTemplate =await _ruleRepository.GetListAsync(val => true); - var ruleMap = ruleTemplate.ToDictionary(val => val.Id); - var result = new List(); - foreach (var item in factors) - { - if(!ruleMap.TryGetValue(item.RuleId,out var rule)) - continue; - var ruleFactors = EntityToRuleFactor(item, rule); - result.AddRange(ruleFactors); - } + [NonAction] + public void ClearRuleCache() + { + RedisHelper.Client.DelAsync(GetRuleKey()); + } - return result; - } - - private ForewarningRule[] RuleEntityToRule(RuleCollectEntity entity) - { - var result = RuleCollectToRule(entity); - if (string.IsNullOrEmpty(entity.Month)) - { - return new ForewarningRule[] { result }; - } + private async Task> GenerateAllRuleFactor() + { + var factors = await _ruleFactorRepository.GetAllList(); + var ruleTemplate = await _ruleRepository.GetListAsync(val => true); + var ruleMap = ruleTemplate.ToDictionary(val => val.Id); + var result = new List(); + foreach (var item in factors) + { + if (!ruleMap.TryGetValue(item.RuleId, out var rule)) + continue; + var ruleFactors = EntityToRuleFactor(item, rule); + result.AddRange(ruleFactors); + } - var months = entity.Month.Split('/'); - var rules = new List(months.Length); + return result; + } - foreach (var month in months) - { - if (int.TryParse(month, out int monthInt)) - { - var rule = result; - rule.Month = monthInt; - rules.Add(rule); - } - } + private ForewarningRule[] RuleEntityToRule(RuleItemEntity entity) + { + var result = RuleCollectToRule(entity); + if (string.IsNullOrEmpty(entity.Month)) + { + return new ForewarningRule[] { result }; + } - return rules.ToArray(); - } + var months = entity.Month.Split('/'); + var rules = new List(months.Length); - private ForewarningRule RuleCollectToRule(RuleCollectEntity entity) - { - return new ForewarningRule - { - Id = entity.Id, - RuleId = entity.RuleId, - Remind = entity.Remind, - Timeliness = entity.Timeliness, - Count = entity.Count, - TrackStart = entity.TrackStart, - TrackEnd = entity.TrackEnd, - CargoType = entity.CargoType, - Month = null, - Area = entity.Area, - IsTransit = entity.IsTransit, - DeparturePort = entity.DeparturePort, - ProductCode = entity.ProductCode - }; - } + foreach (var month in months) + { + if (int.TryParse(month, out int monthInt)) + { + var rule = result; + rule.Month = monthInt; + rules.Add(rule); + } + } - private List EntityToRuleFactor(RuleFactorEntity entity,RuleEntity ruleTemplate) - { - List result = new List(); - foreach (var track in entity.Tracks) - { - var item = new RuleFactor() - { - CustomerId = ruleTemplate.CustomId, - RuleId = ruleTemplate.Id, - NotifyUser = track.NotifyUser, - NotifyTemplate = track.NotifyTemplate, - FactorItems = entity.FactorItems, - End = track.End, - Start = track.Start, - SystemId = ruleTemplate.SubSystemId - }; - result.Add(item); - } + return rules.ToArray(); + } - return result; - } + private ForewarningRule RuleCollectToRule(RuleItemEntity entity) + { + return new ForewarningRule + { + Id = entity.Id, + RuleId = entity.RuleId, + Remind = entity.Remind, + Timeliness = entity.Timeliness, + Count = entity.Count, + TrackStart = entity.TrackStart, + TrackEnd = entity.TrackEnd, + CargoType = entity.CargoType, + Month = null, + Area = entity.Area, + IsTransit = entity.IsTransit, + DeparturePort = entity.DeparturePort, + ProductCode = entity.ProductCode + }; + } + + private List EntityToRuleFactor(RuleFactorEntity entity, RuleEntity ruleTemplate) + { + List result = new List(); + foreach (var track in entity.Tracks) + { + var item = new RuleFactor() + { + CustomerId = ruleTemplate.CustomId, + RuleId = ruleTemplate.Id, + NotifyUser = track.NotifyUser, + NotifyTemplate = track.NotifyTemplate, + FactorItems = entity.FactorItems, + End = track.End, + Start = track.Start, + SystemId = ruleTemplate.SubSystemId + }; + result.Add(item); + } + + return result; + } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs similarity index 71% rename from src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs rename to src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs index b48a7186..c06aa847 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleCollectRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs @@ -2,12 +2,12 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; -public interface IRuleCollectRepository:IBasicRepository +public interface IRuleItemRepository : IBasicRepository { /// /// 查询分页 /// /// /// - Task> QueryForewarningRule(QueryForewarningRuleRequest input); + Task> QueryForewarningRuleItemsAsync(QueryForewarningRuleRequest input); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs index 04a32139..04488ef5 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs @@ -2,11 +2,11 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; -public interface IRuleRepository:IBasicRepository +public interface IRuleRepository : IBasicRepository { - Task CreateForewarning(RuleEntity rule, RuleCollectEntity[] factorList); - - Task UpdateForewarning(RuleEntity rule, RuleCollectEntity[] factorList); + Task CreateForewarning(RuleEntity rule, RuleItemEntity[] ruleItems); - Task> QueryForewarning(QueryForewarningRequest input); + Task UpdateForewarning(RuleEntity rule, RuleItemEntity[] factorList); + + Task> QueryForewarningRuleAsync(QueryForewarningRequest input); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs index b356b062..0b99b712 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs @@ -5,14 +5,14 @@ using SJZY.Track.Domain.Consts; namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; [ElasticsearchType(RelationName = GlobalConst.RuleFactorIndex)] -public class RuleFactorEntity:IdBaseIndex +public class RuleFactorEntity : IdBaseIndex { /// /// RuleId 表的id /// [Keyword(Index = true)] public int RuleId { get; set; } - + /// /// 获取或设置规则跟踪状态实体的列表。 /// @@ -52,4 +52,4 @@ public class RuleFactorEntity:IdBaseIndex /// 获取或设置产品编号的列表。 /// public List ProductCodes { get; set; } -} +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs similarity index 92% rename from src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs rename to src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs index ba4648e2..b08b1edc 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleCollectEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs @@ -1,16 +1,15 @@ namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; -[SugarTable("t_rule_collect")] -public class RuleCollectEntity : IAggregateRoot,ICloneable +[SugarTable("t_rule_item")] +public class RuleItemEntity : IAggregateRoot, ICloneable { /// /// 自增主键 /// [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } - - [SugarColumn(ColumnName = "RuleId")] - public int RuleId { get; set; } + + [SugarColumn(ColumnName = "RuleId")] public int RuleId { get; set; } /// /// 提醒的时间(小时) @@ -29,7 +28,7 @@ public class RuleCollectEntity : IAggregateRoot,ICloneable /// [SugarColumn(ColumnName = "Count")] public int Count { get; set; } - + /// /// 起始轨迹 /// @@ -59,19 +58,19 @@ public class RuleCollectEntity : IAggregateRoot,ICloneable /// [SugarColumn(ColumnName = "Area")] public int? Area { get; set; } - + /// /// 是否中转 /// [SugarColumn(ColumnName = "IsTransit")] public bool? IsTransit { get; set; } - + /// /// 起运港口 /// [SugarColumn(ColumnName = "DeparturePort")] public string DeparturePort { get; set; } - + /// /// 产品编码 /// diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs index cc1d5168..c3c906d9 100644 --- a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs @@ -2,7 +2,7 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; -public interface IKpiAreaRepository:IBasicRepository +public interface IKpiAreaRepository : IBasicRepository { /// /// 创建分区 @@ -45,7 +45,7 @@ public interface IKpiAreaRepository:IBasicRepository /// /// Task> GetAreas(QueryAreaRequest query); - + /// /// 获取分区信息 /// @@ -58,7 +58,7 @@ public interface IKpiAreaRepository:IBasicRepository /// /// /// - Task GetAreaInfoById(int id); + Task GetAreaInfoById(int id); /// /// 获取所有区域信息 diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs index 601821e5..9717997a 100644 --- a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -1,17 +1,16 @@ using SJZY.Track.Domain; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Repository.Repositories; -public class KpiAreaRepository:BasicRepository ,IKpiAreaRepository,ITransientDependency +public class KpiAreaRepository : BasicRepository, IKpiAreaRepository, ITransientDependency { public async ValueTask CreateAreaAsync(RuleAreaEntity entity) { - return await InsertReturnIdentityAsync(entity); + return await InsertReturnIdentityAsync(entity); } - + public async ValueTask AddAreaInfoAsync(RuleAreaInfoEntity entity) { return await Context.Insertable(entity).ExecuteReturnIdentityAsync(); @@ -24,12 +23,12 @@ public class KpiAreaRepository:BasicRepository ,IKpiAreaReposito await Context.Deleteable().Where(x => x.AreaId == areaId).ExecuteCommandAsync(); transaction.Complete(); } - + public Task DeleteAreaInfo(int areaInfoId) { - return Context.Deleteable().Where(val=>val.Id==areaInfoId).ExecuteCommandAsync(); + return Context.Deleteable().Where(val => val.Id == areaInfoId).ExecuteCommandAsync(); } - + public Task UpdateAreaInfoAsync(RuleAreaInfoEntity entity) { return Context.Updateable(entity).ExecuteCommandAsync(); @@ -47,14 +46,14 @@ public class KpiAreaRepository:BasicRepository ,IKpiAreaReposito { queryable = queryable.Where(x => x.Name.Contains(query.Name)); } - + if (query.SystemId.HasValue) { queryable = queryable.Where(x => x.SubSystemId == query.SystemId.Value); } - + return await queryable.OrderBy(x => x.Id, OrderByType.Desc) - .Select(val=>new AreaDto() + .Select(val => new AreaDto() { Id = val.Id, Name = val.Name, @@ -74,7 +73,7 @@ public class KpiAreaRepository:BasicRepository ,IKpiAreaReposito var queryable = Context.Queryable(); queryable = queryable.Where(x => x.AreaId == query.AreaId); return await queryable.OrderBy(x => x.Id, OrderByType.Desc) - .Select(val=>new RuleAreaInfoDto() + .Select(val => new RuleAreaInfoDto() { Id = val.Id, AreaId = val.AreaId, @@ -87,9 +86,9 @@ public class KpiAreaRepository:BasicRepository ,IKpiAreaReposito .ToPagedListAsync(query.PageIndex, query.PageSize); } - public Task GetAreaInfoById(int id) + public Task GetAreaInfoById(int id) { - return Context.Queryable().FirstAsync(val => val.Id == id); + return Context.Queryable().FirstAsync(val => val.Id == id)!; } /// diff --git a/src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs similarity index 80% rename from src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs rename to src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs index 250eedf1..03139fb6 100644 --- a/src/SJZY.Track.Repository/Repositories/RuleCollectRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs @@ -3,28 +3,28 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Repository.Repositories; -public class RuleCollectRepository: BasicRepository, IRuleCollectRepository,ITransientDependency +public class RuleItemRepository : BasicRepository, IRuleItemRepository, ITransientDependency { /// /// 查询预警规则分页信息 /// /// /// - public Task> QueryForewarningRule(QueryForewarningRuleRequest input) + public Task> QueryForewarningRuleItemsAsync(QueryForewarningRuleRequest input) { - var query = Context.Queryable() + var query = Context.Queryable() .Where(val => val.RuleId == input.RuleId); - + if (!string.IsNullOrEmpty(input.SortField)) { query = query.OrderByPropertyName(input.SortField, input.IsAsc ? OrderByType.Asc : OrderByType.Desc); } - - return query.Select(val=>MapToDto(val)) + + return query.Select(val => MapToDto(val)) .ToPagedListAsync(input.PageIndex, input.PageSize); } - private RuleCollectDto MapToDto(RuleCollectEntity entity) + private RuleCollectDto MapToDto(RuleItemEntity entity) { return new RuleCollectDto() { diff --git a/src/SJZY.Track.Repository/Repositories/RuleRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleRepository.cs index 4867ab3f..a285017a 100644 --- a/src/SJZY.Track.Repository/Repositories/RuleRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/RuleRepository.cs @@ -4,27 +4,28 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Repository.Repositories; -public class RuleRepository:BasicRepository ,IRuleRepository,ITransientDependency +public class RuleRepository : BasicRepository, IRuleRepository, ITransientDependency { - public async Task CreateForewarning(RuleEntity rule, RuleCollectEntity[] factorList) + public async Task CreateForewarning(RuleEntity rule, RuleItemEntity[] ruleItems) { using var tran = TransactionHelper.GetReadCommitted(); var ruleId = await InsertReturnIdentityAsync(rule); - foreach (var item in factorList) + foreach (var item in ruleItems) { item.RuleId = ruleId; } - await Context.Insertable(factorList).ExecuteCommandAsync(); + + await Context.Insertable(ruleItems).ExecuteCommandAsync(); tran.Complete(); return ruleId; } - - public async Task UpdateForewarning(RuleEntity rule,RuleCollectEntity[] factorList) + + public async Task UpdateForewarning(RuleEntity rule, RuleItemEntity[] factorList) { using var tran = TransactionHelper.GetReadCommitted(); await UpdateAsync(rule); - await Context.Deleteable().Where(x=>x.RuleId==rule.Id).ExecuteCommandAsync(); + await Context.Deleteable().Where(x => x.RuleId == rule.Id).ExecuteCommandAsync(); await Context.Insertable(factorList).ExecuteCommandAsync(); tran.Complete(); } @@ -34,12 +35,13 @@ public class RuleRepository:BasicRepository ,IRuleRepository,ITransi /// /// /// - public Task> QueryForewarning(QueryForewarningRequest input) + public Task> QueryForewarningRuleAsync(QueryForewarningRequest input) { var query = Context.Queryable() - .WhereIF(input.SystemId.HasValue,val=>val.SubSystemId == input.SystemId) - .WhereIF(string.IsNullOrEmpty(input.KeyWord), val=> val.CustomName.Contains(input.KeyWord)||val.Name.Contains(input.KeyWord)); - + .WhereIF(input.SystemId.HasValue, val => val.SubSystemId == input.SystemId) + .WhereIF(!string.IsNullOrEmpty(input.KeyWord), + val => val.CustomName.Contains(input.KeyWord!) || val.Name.Contains(input.KeyWord!)); + if (!string.IsNullOrEmpty(input.SortField)) { query = query.OrderByPropertyName(input.SortField, input.IsAsc ? OrderByType.Asc : OrderByType.Desc); @@ -47,7 +49,4 @@ public class RuleRepository:BasicRepository ,IRuleRepository,ITransi return query.ToPagedListAsync(input.PageIndex, input.PageSize); } - - - } \ No newline at end of file From fdcc81ba0e172fe119a123a101388011475ddacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Wed, 24 Jul 2024 14:22:53 +0800 Subject: [PATCH 18/60] =?UTF-8?q?fix=EF=BC=9A=E3=80=90=E3=80=90=E8=BD=A8?= =?UTF-8?q?=E8=BF=B9=E8=AE=A2=E5=8D=95pet=E3=80=91=E5=B9=B2=E7=BA=BF?= =?UTF-8?q?=E6=8F=90=E5=8D=95=E6=96=B0=E5=A2=9E=E8=BD=A8=E8=BF=B9=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E6=9C=AA=E6=8E=A8=E9=80=81=E5=88=B0=E7=AE=B1=E5=8D=95?= =?UTF-8?q?=E5=92=8C=E5=B0=8F=E5=8C=85=E8=BF=90=E8=BE=93=E5=8D=95=E4=B8=8A?= =?UTF-8?q?=E3=80=91https://www.tapd.cn/60863849/bugtrace/bugs/view/116086?= =?UTF-8?q?3849001043303?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CAP/EventHandlers/TrackUpsertEventHandler.cs | 6 ++++-- src/SJZY.Track.Domain/Queries/IProvideQueries.cs | 2 +- src/SJZY.Track.Repository/Queries/ProvideQueries.cs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index 46443ffb..bd8ef2c3 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -103,6 +103,10 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe private async Task HandleTrackAsync(TrackUpsertEvent @event, List canNextOrderIds) { + var content = await _provideQueries.GetTrackContentAsync(@event.SubSystemId, @event.TrackCode); + + if (content == null) return; + var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); var tracks = await _trackDetailsRepository.GetListAsync(orderIds, @event.TrackCode, true); @@ -170,8 +174,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe if (canNextOrderIds.Count == 0) return; - var content = await _provideQueries.GetTrackContentAsync(@event.SubSystemId, @event.TrackCode); - // 批量add to es await _trackDetailsRepository.AddManyAsync(insertTracks); diff --git a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs index 34e99ae9..e01e5a50 100644 --- a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs +++ b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs @@ -67,5 +67,5 @@ public interface IProvideQueries Task> FindOrderWithServiceProviderAsync(int serviceProvider, int pageIndex, int pageSize = 1000); - Task GetTrackContentAsync(int subSystemId, string trackCode); + Task GetTrackContentAsync(int subSystemId, string trackCode); } \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs index f2a9f25c..8cf2cf5f 100644 --- a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs +++ b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs @@ -137,7 +137,7 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, .ToListAsync(); } - public async Task GetTrackContentAsync(int subSystemId, string trackCode) + public async Task GetTrackContentAsync(int subSystemId, string trackCode) { return await Context.Queryable() .LeftJoin((x, y) => x.TrackStatusId == y.Id) From f42287a7f83fcd7345491dc9b079d25f3cc5160b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=86=9B?= <2357729423@qq.com> Date: Wed, 24 Jul 2024 15:15:44 +0800 Subject: [PATCH 19/60] temp --- .../Events/TrackChangeAfterUpdateOrderEvent.cs | 5 +++++ .../CAP/EventHandlers/TrackUpsertEventHandler.cs | 1 + src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs | 5 +++++ src/SJZY.Track.Repository/Queries/ProvideQueries.cs | 1 + 4 files changed, 12 insertions(+) diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs index a59c31c8..b52a95a3 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -22,6 +22,11 @@ public class TrackChangeAfterUpdateOrderEvent /// public string TrackEnContent { get; set; } = null!; + /// + /// 轨迹状态Id + /// + public int TrackStatusId { get; set; } + /// /// 轨迹发生地 /// diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index bd8ef2c3..baa3d8b3 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -185,6 +185,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe IsCompleted = @event.TrackRefreshData.IsCompleted, TrackContent = content.TrackContent, TrackEnContent = content.TrackEnContent, + TrackStatusId = content.TrackStatusId, TrackPlace = @event.TrackPlace, TrackTime = @event.TrackTime, TrackTimeZone = @event.TrackTimeZone diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs index d44e75c8..0c0f13d5 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs @@ -2,6 +2,11 @@ public class TrackContentVO { + /// + /// 轨迹状态Id + /// + public int TrackStatusId { get; set; } + /// /// 轨迹状态 /// diff --git a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs index 8cf2cf5f..5ffffe7a 100644 --- a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs +++ b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs @@ -144,6 +144,7 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, .Where(x => x.SubSystemId == subSystemId && x.Code == trackCode) .Select((x, y) => new TrackContentVO { + TrackStatusId = x.TrackStatusId, TrackStatus = y.Status, TrackContent = x.Content, TrackEnContent = x.EnContent From d67c7ce820ed5f3e4047a6e8b299b54dbf7a73e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Thu, 25 Jul 2024 09:26:07 +0800 Subject: [PATCH 20/60] =?UTF-8?q?feat:=20=E8=BD=A8=E8=BF=B9=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E7=95=8C=E9=9D=A2=E7=9A=84=E6=8E=A8=E9=80=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=A2=9E=E5=8A=A0=E6=8E=A8=E9=80=81=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrackPush/EditTrackPushConfigInput.cs | 19 +++++++++- .../TrackPush/TrackPushContentConfigDto.cs | 20 +++++++++- .../EventHandlers/TrackPushEventHandler.cs | 11 +++++- .../Helpers/DateTimeHelper.cs | 36 ++++++++++++++++++ .../TrackPush/TrackPushCacheService.cs | 5 ++- .../TrackPushConfigEntity.cs | 22 ++++++++++- .../Enums/DateTimeFormatEnum.cs | 17 +++++++++ .../Enums/TimezoneSourceEnum.cs | 37 +++++++++++++++++++ 8 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 src/SJZY.Track.Application/Helpers/DateTimeHelper.cs create mode 100644 src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs create mode 100644 src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs index b4ed8f6e..bb4b0066 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs @@ -1,4 +1,6 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPush; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; public class EditTrackPushConfigInput { @@ -48,4 +50,19 @@ public class EditTrackPushConfigInput /// 是否全量推送 /// public bool? IsAllPush { get; set; } + + /// + /// 时间格式枚举 + /// + public DateTimeFormatEnum DateTimeFormatType { get; set; } + + /// + /// 日期时间格式模板 + /// + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + public string? TimezoneFormat { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs index c2bcf867..f778ada8 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs @@ -1,4 +1,6 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPush; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; public class TrackPushContentConfigDto { @@ -71,4 +73,20 @@ public class TrackPushContentConfigDto /// 扩展字段参数值 /// public string? ExpandFieldsValue { get; set; } + + + /// + /// 时间格式枚举 + /// + public DateTimeFormatEnum DateTimeFormatType { get; set; } + + /// + /// 日期时间格式模板 + /// + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + public string? TimezoneFormat { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs index 734246eb..cd7ec8f7 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs @@ -86,7 +86,9 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe if (config == null) continue; if (!config.IsAutoPush) continue; if (config.OrderType != order.OrderType) continue; - + + // todo 确认是不是这里转换 + DateTimeFormat( @event.SystemPushInfo.TrackTime,"yyyy-MM-dd HH:mm:ss"); var log = new TrackPushRecordIndex { OptionType = @event.OptionType.ToString(), @@ -159,6 +161,12 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe throw new BusinessException(message: $"requestId: {r.RequestId}; {r.Msg}"); } } + + + private string DateTimeFormat(DateTime dateTime,string format) + { + return dateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } private async Task DoUpdateAsync(TrackPushEvent @event) { @@ -250,6 +258,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe if (config.IsAllPush) { + //todo 这个是指每次都带上之前的轨迹嘛 var history = await _trackPushRecordsRepository.GetLatestTrackPushRecordAsync(log.OrderId); if (history != default) { diff --git a/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs new file mode 100644 index 00000000..b0f3e0bd --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs @@ -0,0 +1,36 @@ +namespace SJZY.Track.Application.Helpers; + +public static class DateTimeHelper +{ + /// + /// Generates a Unix timestamp from a DateTime object. + /// + /// The DateTime object to convert to a Unix timestamp. + /// The Unix timestamp as a long. + public static long GenerateUnixTimestamp(DateTime dateTime) + { + return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); + } + + /// + /// Formats a DateTime object into a specified format. + /// + /// The DateTime object to format. + /// The format string. + /// The formatted date string. + public static string FormatDateTime(DateTime dateTime, string format) + { + return dateTime.ToString(format); + } + + /// + /// 时区格式化 + /// + /// + /// + /// + public static string TimezoneFormat(float timezone, string format) + { + return string.Format(format, timezone); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs b/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs index dfda8279..31e38468 100644 --- a/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs +++ b/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs @@ -48,7 +48,7 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc var trackPushConfig = await _trackPushConfigRepository.GetFirstAsync( x => x.SubSystemId == subSystemId && x.CustomId == customId, x => new { - x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId + x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId,x.DateTimeFormatType,x.DateTimeFormat,x.TimezoneFormat }); if (trackPushConfig == null) { @@ -68,6 +68,9 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc IsCanUpdate = trackPushConfig.IsCanUpdate, IsAllPush = trackPushConfig.IsAllPush, IsCanDelete = trackPushConfig.IsCanDelete, + DateTimeFormatType = trackPushConfig.DateTimeFormatType, + DateTimeFormat = trackPushConfig.DateTimeFormat, + TimezoneFormat = trackPushConfig.TimezoneFormat, ServiceProviderCode = item.ServiceProviderCode, OrderType = item.OrderType, TrackCode = item.TrackCode, diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs index 659e3281..8398a0bf 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs @@ -1,4 +1,6 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; /// /// 轨迹推送配置表 @@ -53,4 +55,22 @@ public class TrackPushConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "IsAllPush")] public bool IsAllPush { get; set; } + + /// + /// 日期时间格式类型 + /// + [SugarColumn(ColumnName = "DateTimeFormatType")] + public DateTimeFormatEnum DateTimeFormatType { get; set; } + + /// + /// 日期时间格式模板 + /// + [SugarColumn(ColumnName = "DateTimeFormat")] + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + [SugarColumn(ColumnName = "TimezoneFormat")] + public string? TimezoneFormat { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs b/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs new file mode 100644 index 00000000..37e3c4fc --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs @@ -0,0 +1,17 @@ +namespace SJZY.Track.Domain.Enums; + +/// +/// 时间样式枚举 +/// +public enum DateTimeFormatEnum +{ + /// + /// 时间戳 + /// + Timestamp=1, + + /// + /// 时间加时区 + /// + DateTimeAndTimezone =2 +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs b/src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs new file mode 100644 index 00000000..70aca24a --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs @@ -0,0 +1,37 @@ +namespace SJZY.Track.Domain.Enums; + +/// +/// 推送轨迹时区来源 +/// +public enum TimezoneSourceEnum +{ + /// + /// 起运城市 + /// + DeliverCity = 1, + + /// + /// 接收城市 + /// + ReceiveCity = 2, + + /// + /// 起运港口 + /// + DeliverPort = 3, + + /// + /// 接收港口 + /// + ReceivePort = 4, + + /// + /// 起运国家 + /// + DeliverCountry = 5, + + /// + /// 接收国家 + /// + ReceiveCountry = 6 +} \ No newline at end of file From 2f5354960d6b619ce4a6ebf91aafb3b40743a942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Thu, 25 Jul 2024 10:32:01 +0800 Subject: [PATCH 21/60] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=85=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helpers/ForewarningFactorHelper.cs | 7 ++++- .../ForewarningServices/ForewarningService.cs | 6 ++-- .../ForewarningServices/KpiAreaService.cs | 1 - .../RuleTrackStateModel.cs | 6 +--- .../Forewarning/AddRuleAreaInfoRequest.cs | 28 +++++++++++++++---- .../Forewarning/ModifyTimelinessRequest.cs | 8 +++++- .../Dtos/Forewarning/QueryAreaInfoRequest.cs | 3 ++ .../Forewarning/UpdateRuleAreaInfoRequest.cs | 20 ++++++++++++- .../Dtos/Forewarning/UpdateRuleAreaRequest.cs | 2 +- 9 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs index 5490aea1..e3a1f4c9 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs @@ -9,6 +9,11 @@ public class ForewarningFactorHelper { var total = Factorial(ruleFactors); var ruleCollect = AllocateFactor(total, ruleFactors.RuleId); + Assignment(ruleCollect, total, ruleFactors.Tracks, (item, value) => + { + item.TrackEnd = value.End; + item.TrackStart = value.Start; + }); Assignment(ruleCollect, total, ruleFactors.CargoTypes, (item, value) => item.CargoType = value); Assignment(ruleCollect, total, ruleFactors.Months, (item, value) => item.Month = value); Assignment(ruleCollect, total, ruleFactors.Areas, (item, value) => item.Area = value); @@ -54,7 +59,7 @@ public class ForewarningFactorHelper internal static int Factorial(RuleFactorEntity ruleFactors) { - return ruleFactors.CargoTypes.Count * ruleFactors.Months.Count * ruleFactors.Areas.Count * + return ruleFactors.Tracks.Count* ruleFactors.CargoTypes.Count * ruleFactors.Months.Count * ruleFactors.Areas.Count * ruleFactors.IsTransit.Count * ruleFactors.DeparturePorts.Count * ruleFactors.ProductCodes.Count; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index b9544324..11532104 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -9,9 +9,9 @@ namespace SJZY.Track.Application.Services.ForewarningServices; public class ForewarningService : ApplicationService { readonly IRuleRepository _ruleRepository; - IRuleFactorRepository _ruleFactorRepository; - private IRuleItemRepository _ruleItemRepository; - + readonly IRuleFactorRepository _ruleFactorRepository; + private readonly IRuleItemRepository _ruleItemRepository; + public ForewarningService(IRuleRepository ruleRepository , IRuleFactorRepository ruleFactorRepository , IRuleItemRepository ruleItemRepository) diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs index 3fc7c3ac..593467ef 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -95,7 +95,6 @@ public class KpiAreaService : ApplicationService if (input.Id <= 0) return new UnifyResultDto(false, "id不能为空"); - //todo 测试不存在id的情况 var areaInfo = await _ruleAreaRepository.GetAreaInfoById(input.Id); if (areaInfo == null) return new UnifyResultDto(false, "未找到该区域信息"); diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs index 554d1e2c..a4605dcb 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs @@ -16,9 +16,5 @@ public class RuleTrackStateModel /// Gets or sets the user to notify. /// public string NotifyUser { get; set; } - - /// - /// Gets or sets the notification template. - /// - public string NotifyTemplate { get; set; } + } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs index 789dd29f..08616063 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs @@ -4,17 +4,35 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public class AddRuleAreaInfoRequest { + /// + /// 国家名称,必填项。 + /// [Required] public string Country { get; set; } - + + /// + /// 省份名称,可为空。 + /// public string? Province { get; set; } - + + /// + /// 城市名称,可为空。 + /// public string? City { get; set; } - + + /// + /// 左侧邮政编码,可为空。 + /// public string? LeftPostCode { get; set; } - + + /// + /// 右侧邮政编码,可为空。 + /// public string? RightPostCode { get; set; } - + + /// + /// 区域ID,必填项。 + /// [Required] public int AreaId { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs index 8b023cac..841292f7 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs @@ -2,6 +2,9 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public class ModifyTimelinessRequest { + /// + /// 规则详情中的时效相关信息 + /// public List Items { get; set; } /// @@ -10,6 +13,9 @@ public class ModifyTimelinessRequest public int RuleId { get; set; } } +/// +/// 规则详情时效 +/// public class TimelinessDto { /// @@ -28,7 +34,7 @@ public class TimelinessDto public int Count { get; set; } /// - /// 规则id + /// 规则详情id /// public int Id { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs index 196a65bf..896f47a7 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs @@ -2,5 +2,8 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public class QueryAreaInfoRequest: PageInfoInput { + /// + /// 区域id + /// public int AreaId { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs index c6f52158..29a25f7f 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs @@ -2,21 +2,39 @@ using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Domain.Dtos.Forewarning; +/// +/// 更新规则区域信息请求 +/// public class UpdateRuleAreaInfoRequest { /// - /// 分区信息id + /// 区域信息ID /// public int Id { get; set; } + /// + /// 国家名称,必填项。 + /// [Required] public string Country { get; set; } + /// + /// 省份名称,可为空。 + /// public string? Province { get; set; } + /// + /// 城市名称,可为空。 + /// public string? City { get; set; } + /// + /// 左侧邮政编码,可为空。 + /// public string? LeftPostCode { get; set; } + /// + /// 右侧邮政编码,可为空。 + /// public string? RightPostCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs index f0bac318..74ca3538 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs @@ -11,7 +11,7 @@ public class UpdateRuleAreaRequest public string Name { get; set; } /// - /// 分区id + /// 区域id /// public int Id { get; set; } } \ No newline at end of file From 740bc61558c312068e08057f1ecf083168c672f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Thu, 25 Jul 2024 10:33:14 +0800 Subject: [PATCH 22/60] =?UTF-8?q?feat:=20=E8=BF=98=E5=8E=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aggregates/ForewarningAggregate/RuleTrackStateModel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs index a4605dcb..554d1e2c 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs @@ -16,5 +16,9 @@ public class RuleTrackStateModel /// Gets or sets the user to notify. /// public string NotifyUser { get; set; } - + + /// + /// Gets or sets the notification template. + /// + public string NotifyTemplate { get; set; } } \ No newline at end of file From aae9add71c9bf6ce004568285df71a2724225d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Thu, 25 Jul 2024 15:03:47 +0800 Subject: [PATCH 23/60] =?UTF-8?q?feat:=20=E8=BD=A8=E8=BF=B9=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E7=95=8C=E9=9D=A2=E7=9A=84=E6=8E=A8=E9=80=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=A2=9E=E5=8A=A0=E6=8E=A8=E9=80=81=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=20=E5=BC=80=E5=8F=91=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/TrackPush/TrackPushInput.cs | 2 +- .../EventHandlers/TrackPushEventHandler.cs | 50 +++++++++++++------ .../Helpers/DateTimeHelper.cs | 11 ++-- .../ProvideServices/TrackPushService.cs | 24 ++++++++- 4 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs index bc1d10bc..28a18876 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs @@ -21,7 +21,7 @@ public class TrackUpdateInput public class TrackItem { public string Location { get; set; } = null!; - public DateTime Date { get; set; } + public string Date { get; set; } public double TimeZone { get; set; } public string? Description { get; set; } public string? DescriptionCn { get; set; } diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs index cd7ec8f7..30ef3bdc 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs @@ -1,4 +1,5 @@ -using DotNetCore.CAP; +using System.Globalization; +using DotNetCore.CAP; using Newtonsoft.Json; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.InterfaceRelay.Application.Contracts; @@ -87,8 +88,6 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe if (!config.IsAutoPush) continue; if (config.OrderType != order.OrderType) continue; - // todo 确认是不是这里转换 - DateTimeFormat( @event.SystemPushInfo.TrackTime,"yyyy-MM-dd HH:mm:ss"); var log = new TrackPushRecordIndex { OptionType = @event.OptionType.ToString(), @@ -114,7 +113,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe var tracks = await _trackDetailsRepository.GetListAsync(@event.OrderIds, @event.TrackCode); tracks = tracks.DistinctBy(x => x.OrderId).ToList(); // 防止重复推送 - + var temp=this.DateTimeFormat(DateTime.Now, -8.0, config); if (tracks.Count == 0) return; // 一个能推的轨迹都不存在 // tips:人工推送只要能推就推了,不会校验已推和顺序问题,因为可能是更新 @@ -161,12 +160,6 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe throw new BusinessException(message: $"requestId: {r.RequestId}; {r.Msg}"); } } - - - private string DateTimeFormat(DateTime dateTime,string format) - { - return dateTime.ToString("yyyy-MM-dd HH:mm:ss"); - } private async Task DoUpdateAsync(TrackPushEvent @event) { @@ -210,12 +203,14 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe private TrackUpdateInput BuiltUpdateItem(TrackPushContentConfigDto config, TrackPushRecordIndex log) { + var trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone); + var trackDateStr = DateTimeFormat(trackDatetime,config.TrackTimeZone ?? log.TrackTimeZone,config); + var track = new TrackItem { // 推真实的发生地和发生时间(时间是计算后的) Location = log.TrackPlace, - Date = log.TrackTime.AddHours( - config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone), + Date = trackDateStr, TimeZone = config.TrackTimeZone ?? log.TrackTimeZone, Description = config.TrackEnContentValue, DescriptionCn = config.TrackContentValue, @@ -236,12 +231,14 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe private async Task BuiltPushItem(TrackPushContentConfigDto config, TrackPushRecordIndex log) { + var trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone); + var trackDateStr = DateTimeFormat(trackDatetime,config.TrackTimeZone ?? log.TrackTimeZone,config); + var track = new TrackItem { // 推真实的发生地和发生时间(时间是计算后的) Location = log.TrackPlace, - Date = log.TrackTime.AddHours( - config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone), + Date = trackDateStr, TimeZone = config.TrackTimeZone ?? log.TrackTimeZone, Description = config.TrackEnContentValue, DescriptionCn = config.TrackContentValue, @@ -258,7 +255,6 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe if (config.IsAllPush) { - //todo 这个是指每次都带上之前的轨迹嘛 var history = await _trackPushRecordsRepository.GetLatestTrackPushRecordAsync(log.OrderId); if (history != default) { @@ -296,4 +292,28 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe return matched != null && matched.TrackCode == trackCode ? matched : default; } + + /// + /// 转换推送时间格式 + /// + /// + /// + /// + /// + private string DateTimeFormat(DateTime dateTime,double timezone, TrackPushContentConfigDto config) + { + if (config.DateTimeFormatType == DateTimeFormatEnum.Timestamp) + return DateTimeHelper.ConvertToUnixTimestamp(dateTime).ToString(); + + if (config.DateTimeFormatType == DateTimeFormatEnum.DateTimeAndTimezone + && !string.IsNullOrEmpty(config.DateTimeFormat) + && !string.IsNullOrEmpty(config.TimezoneFormat)) + { + var zoneStr = DateTimeHelper.TimezoneFormat(timezone, config.TimezoneFormat); + var datetimeStr = DateTimeHelper.FormatDateTime(dateTime, config.DateTimeFormat); + return $"{datetimeStr} {zoneStr}"; + } + + return dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK"); + } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs index b0f3e0bd..907cab70 100644 --- a/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs +++ b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs @@ -1,13 +1,15 @@ +using SJZY.OTel; + namespace SJZY.Track.Application.Helpers; public static class DateTimeHelper { /// - /// Generates a Unix timestamp from a DateTime object. + /// convert to a Unix timestamp from a DateTime object. /// /// The DateTime object to convert to a Unix timestamp. /// The Unix timestamp as a long. - public static long GenerateUnixTimestamp(DateTime dateTime) + public static long ConvertToUnixTimestamp(DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); } @@ -29,8 +31,9 @@ public static class DateTimeHelper /// /// /// - public static string TimezoneFormat(float timezone, string format) + public static string TimezoneFormat(double timezone, string format) { - return string.Format(format, timezone); + //时区是整数丢掉浮点数部分 + return format.Replace("hh", ((int)timezone).ToString()); } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs index 41a91a72..c7663f86 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs @@ -1,5 +1,6 @@ using DotNetCore.CAP; using Microsoft.AspNetCore.Authorization; +using SJZY.Track.Application.CAP.EventHandlers; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Domain.Aggregates.OrderAggregate; @@ -21,16 +22,17 @@ public class TrackPushService : ApplicationService private readonly ICapPublisher _capPublisher; private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; private readonly IHttpClientProxy _requestCurrentUserService; - + TrackPushEventHandler _trackPushEventHandler; public TrackPushService(IOrderRepository orderRepository , ICapPublisher capPublisher , ITrackPushRecordsRepository trackPushRecordsRepository, - IHttpClientProxy requestCurrentUserService) + IHttpClientProxy requestCurrentUserService, TrackPushEventHandler trackPushEventHandler) { _orderRepository = orderRepository; _capPublisher = capPublisher; _trackPushRecordsRepository = trackPushRecordsRepository; _requestCurrentUserService = requestCurrentUserService; + _trackPushEventHandler = trackPushEventHandler; } /// @@ -41,6 +43,24 @@ public class TrackPushService : ApplicationService [HttpPost("Track/Push")] public async Task PushTrackAsync(PushTrackInput input) { + var trackPushEvenst = new TrackPushEvent +{ + OptionType = OptionType.新增, // Assuming OptionType.新增 corresponds to 1 + SubSystemId = 9534, + CustomId = 228618, + OrderIds = new int[] { 1 }, + TrackCode = "CP", + OperationMan = "郑志红", + SystemPushInfo = new SystemPushStruct + { + TrackStatus = null, + TrackContent = null, + TrackPlace = null, + TrackTime = DateTime.Parse("0001-01-01T00:00:00"), + TrackTimeZone = 0.0f + } +}; + await _trackPushEventHandler.ConsumerAsync(trackPushEvenst); input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 var orders = await _orderRepository.GetArrayAsync(x => From c3f904ccdcc44959f24a50318621a4def581c925 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Thu, 25 Jul 2024 21:06:06 +0800 Subject: [PATCH 24/60] =?UTF-8?q?importance=EF=BC=9A=E9=A2=84=E8=AD=A6?= =?UTF-8?q?=E5=88=9D=E6=AD=A5=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Forewarning/ModifyTimeSpanInput.cs | 17 ++ .../Dtos/Forewarning/WarningTimeSpanDto.cs | 27 +++ .../Services/IRuleFactorCacheService.cs | 2 +- .../AutoMapper/ForewarningMapperProfile.cs | 18 +- ...TrackChangeAfterUpdateOrderEventHandler.cs | 6 +- .../TrackPushCompletedEventHandler.cs | 2 +- .../EventHandlers/TrackPushEventHandler.cs | 4 +- .../Helpers/ForewarningFactorHelper.cs | 65 ------ .../Helpers/ForewarningHelper.cs | 139 +++++++++++++ .../ForewarningNotifyService.cs | 34 +-- .../ForewarningServices/ForewarningService.cs | 123 ++++------- .../RuleFactorCacheService.cs | 194 ------------------ .../Forewarning/CreateRuleFactorValidation.cs | 29 +-- .../Forewarning/RuleTrackStateDtoValidator.cs | 9 +- .../ForewarningAggregate/IForewarningList.cs | 8 - .../IRuleFactorRepository.cs | 10 - .../IRuleItemRepository.cs | 13 -- .../ForewarningAggregate/IRuleRepository.cs | 12 -- .../IWarningRepository.cs | 48 +++++ .../ForewarningAggregate/RuleEntity.cs | 60 ------ .../ForewarningAggregate/RuleFactorEntity.cs | 55 ----- .../ForewarningAggregate/RuleItemEntity.cs | 109 ---------- .../RuleTrackStateModel.cs | 24 --- .../ForewarningAggregate/WarningEntity.cs | 53 +++++ .../WarningFactorEntity.cs | 30 +++ .../ForewarningAggregate/WarningRuleEntity.cs | 83 ++++++++ .../Dtos/Forewarning/CreateRuleRequest.cs | 49 ++--- .../Dtos/Forewarning/FactorItemDto.cs | 16 -- ...ewarningRule.cs => ForewarningRuleItem.cs} | 2 +- .../Dtos/Forewarning/GetWarningPageInputVo.cs | 14 ++ ...eRequest.cs => GetWarningRuleListInput.cs} | 2 +- .../Forewarning/ModifyTimelinessRequest.cs | 40 ---- .../Forewarning/QueryForewarningRequest.cs | 24 --- .../Dtos/Forewarning/RuleCollectDto.cs | 22 -- .../Dtos/Forewarning/RuleInfoModel.cs | 42 ---- .../Dtos/Forewarning/RuleTrackStateDto.cs | 24 --- .../Dtos/Forewarning/TrackStatusSpanDto.cs | 19 ++ .../Dtos/Forewarning/WarningFactorDto.cs | 17 ++ .../Dtos/Forewarning/WarningPageOutput.cs | 29 +++ .../Dtos/Forewarning/WarningRuleOutput.cs | 64 ++++++ .../Dtos/Order/GetOrderDetailsInputVO.cs | 18 -- src/SJZY.Track.Domain/Enums/NotifyMode.cs | 14 ++ src/SJZY.Track.Domain/Enums/RuleFactorType.cs | 8 +- .../Repositories/OrderRepository.cs | 2 +- .../Repositories/RuleFactorRepository.cs | 53 ----- .../Repositories/RuleItemRepository.cs | 50 ----- .../Repositories/RuleRepository.cs | 52 ----- .../Repositories/WarningRepository.cs | 75 +++++++ 48 files changed, 732 insertions(+), 1078 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs delete mode 100644 src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs create mode 100644 src/SJZY.Track.Application/Helpers/ForewarningHelper.cs delete mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs delete mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs rename src/SJZY.Track.Domain/Dtos/Forewarning/{ForewarningRule.cs => ForewarningRuleItem.cs} (91%) create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs rename src/SJZY.Track.Domain/Dtos/Forewarning/{QueryForewarningRuleRequest.cs => GetWarningRuleListInput.cs} (87%) delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/WarningFactorDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs create mode 100644 src/SJZY.Track.Domain/Enums/NotifyMode.cs delete mode 100644 src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs delete mode 100644 src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs delete mode 100644 src/SJZY.Track.Repository/Repositories/RuleRepository.cs create mode 100644 src/SJZY.Track.Repository/Repositories/WarningRepository.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs new file mode 100644 index 00000000..016106ec --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs @@ -0,0 +1,17 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class ModifyTimeSpanInput +{ + /// + /// 预警id + /// + public int WarningId { get; set; } + + /// + /// 规则详情中的时效相关信息 + /// + public List Items { get; set; } = new(); +} + diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs new file mode 100644 index 00000000..02c3e20c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs @@ -0,0 +1,27 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +/// +/// 预警规则时效 +/// +public class WarningTimeSpanDto +{ + /// + /// 预警规则id + /// + public int Id { get; set; } + + /// + /// 时效 + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒时效 + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + public int WarnCount { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs index 41eb2171..fb1f742b 100644 --- a/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs @@ -12,7 +12,7 @@ public interface IRuleFactorCacheService /// 获取所有因子收集的规则。 /// /// 规则数组。 - Task GetAllFactorCollect(); + Task GetAllFactorCollect(); /// /// 获取所有规则因子。 diff --git a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs index b905d38d..c06978eb 100644 --- a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; @@ -9,9 +10,8 @@ public class ForewarningMapperProfile :Profile { public ForewarningMapperProfile() { - CreateMap(MemberList.None); - CreateMap(); - CreateMap(); + CreateMap(MemberList.None); + CreateMap(MemberList.None); CreateMap(); CreateMap(MemberList.None); CreateMap(MemberList.None) @@ -32,17 +32,5 @@ public class ForewarningMapperProfile :Profile .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) .ForMember(dest => dest.RightPostcode, opt => opt.MapFrom(src => src.RightPostCode)); - - CreateMap(MemberList.None) - .ForMember(dest => dest.RuleId, opt => opt.MapFrom(src => src.RuleId)) - .ForMember(dest => dest.Tracks, opt => opt.MapFrom(src => src.Tracks)) - .ForMember(dest => dest.FactorItems, opt => opt.MapFrom(src => src.FactorItems)) - .ForMember(dest => dest.CargoTypes, opt => opt.MapFrom(src => src.CargoTypes)) - .ForMember(dest => dest.Months, opt => opt.MapFrom(src => src.Months.Select(m => m.ToString()))) - .ForMember(dest => dest.IsTransit, opt => opt.MapFrom(src => src.IsTransit.Select(i => i == 1))) - .ForMember(dest => dest.Areas, opt => opt.MapFrom(src => src.Areas)) - .ForMember(dest => dest.DeparturePorts, opt => opt.MapFrom(src => src.DeparturePorts)) - .ForMember(dest => dest.ProductCodes, opt => opt.MapFrom(src => src.ProductCodes)); - } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 7a371e49..c20ca137 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -2,7 +2,6 @@ using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; using Volo.Abp.DependencyInjection; @@ -12,15 +11,12 @@ namespace SJZY.Track.Application.CAP.EventHandlers; public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICapSubscribe { private readonly IOrderRepository _orderRepository; - private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly IForewarningNotifyService _forewarningNotifyService; - public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, - ITrackDetailsRepository trackDetailsRepository, + public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, IForewarningNotifyService forewarningNotifyService) { _orderRepository = orderRepository; - _trackDetailsRepository = trackDetailsRepository; _forewarningNotifyService = forewarningNotifyService; } diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs index 4658aa44..b63c4e52 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs @@ -26,7 +26,7 @@ public class TrackPushCompletedEventHandler : ITransientDependency, ICapSubscrib [CapSubscribe(GlobalConst.TrackPushCompletedSubscribe, Group = GlobalConst.TrackPushSubscribe)] public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) { - string logStr = null; + string? logStr = null; var optionType = Base64Helper.DeSerialize(@event.Attach); if (optionType == OptionType.新增.ToString()) { diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs index cd7ec8f7..f28ffc69 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs @@ -23,8 +23,8 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe private readonly ITrackPushCacheService _trackPushCacheService; private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; - private List _pushConfigs; - private List _orders; + private List _pushConfigs = null!; + private List _orders = null!; public TrackPushEventHandler(IHttpClientProxy httpClientProxy, IOrderRepository orderRepository, ITrackPushCacheService trackPushCacheService, diff --git a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs deleted file mode 100644 index e3a1f4c9..00000000 --- a/src/SJZY.Track.Application/Helpers/ForewarningFactorHelper.cs +++ /dev/null @@ -1,65 +0,0 @@ -using JetBrains.Annotations; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -namespace SJZY.Track.Application.Helpers; - -public class ForewarningFactorHelper -{ - public static RuleItemEntity[] GetFactorItem([NotNull] RuleFactorEntity ruleFactors) - { - var total = Factorial(ruleFactors); - var ruleCollect = AllocateFactor(total, ruleFactors.RuleId); - Assignment(ruleCollect, total, ruleFactors.Tracks, (item, value) => - { - item.TrackEnd = value.End; - item.TrackStart = value.Start; - }); - Assignment(ruleCollect, total, ruleFactors.CargoTypes, (item, value) => item.CargoType = value); - Assignment(ruleCollect, total, ruleFactors.Months, (item, value) => item.Month = value); - Assignment(ruleCollect, total, ruleFactors.Areas, (item, value) => item.Area = value); - Assignment(ruleCollect, total, ruleFactors.IsTransit, (item, value) => item.IsTransit = value); - Assignment(ruleCollect, total, ruleFactors.DeparturePorts, (item, value) => item.DeparturePort = value); - Assignment(ruleCollect, total, ruleFactors.ProductCodes, (item, value) => item.ProductCode = value); - return ruleCollect.ToArray(); - } - - private static void Assignment(Span ruleCollect, int total, IReadOnlyList values, - Action action) - { - if (values.Count == 0) - { - return; - } - - var segment = total / values.Count; - for (int index = 0; index < values.Count; index++) - { - var start = index * segment; - var assignmentSlice = ruleCollect.Slice(start, segment); - foreach (var item in assignmentSlice) - { - action(item, values[index]); - } - } - } - - private static Span AllocateFactor(int total, int ruleId) - { - Span factors = new RuleItemEntity[total]; - for (int index = 0; index < total; index++) - { - factors[index] = new RuleItemEntity() - { - RuleId = ruleId - }; - } - - return factors; - } - - internal static int Factorial(RuleFactorEntity ruleFactors) - { - return ruleFactors.Tracks.Count* ruleFactors.CargoTypes.Count * ruleFactors.Months.Count * ruleFactors.Areas.Count * - ruleFactors.IsTransit.Count * ruleFactors.DeparturePorts.Count * ruleFactors.ProductCodes.Count; - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs new file mode 100644 index 00000000..c945e018 --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -0,0 +1,139 @@ +using Newtonsoft.Json.Linq; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Helpers; + +public class ForewarningHelper +{ + /// + /// 递推分裂预警规则列表 + /// + /// + /// + /// + public static List CalcRuleList(List statusSpans, + List factors) + { + var len = statusSpans.Count * factors.Select(f => f.FactorValue.Count).Aggregate((pre, cur) => pre * cur); + if (len == 0) + { + throw new BusinessException(message: "轨迹状态区间或因素列表为空"); + } + + var rules = new List(len); + + var repeat = len / statusSpans.Count; + + FillStatus(statusSpans, rules, repeat); + + foreach (var factor in factors) + { + var factorValueCount = factor.FactorValue.Count; + repeat /= factor.FactorValue.Count; // repeat梯度下降,与times成反比关系 + + for (int time = 0; time < len / repeat / factorValueCount; time++) + { + FillFactor(factor, rules, repeat, time); + } + } + + + return rules; + } + + private static void FillStatus(List statusSpans, List rules, int repeat) + { + for (var i = 0; i < statusSpans.Count; i++) + { + var span = statusSpans[i]; + + for (var j = 0; j < repeat; j++) + { + var row = i * repeat + j; + rules[row].StartTrackStatusId = span.StartTrackStatusId; + rules[row].EndTrackStatusId = span.EndTrackStatusId; + } + } + } + + private static void FillFactor(WarningFactorDto factor, List rules, int repeat, int time) + { + for (var i = 0; i < factor.FactorValue.Count * time; i++) + { + for (var j = 0; j < repeat; j++) + { + var row = i * repeat + j; + var value = factor.FactorValue[row]; + var strValue = value.ToString(); + switch (factor.FactorType) + { + case RuleFactorType.CargoType: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "货物类型只接收字符串"); + } + + rules[row].CargoType = strValue; + break; + case RuleFactorType.Months: + foreach (var item in strValue.Split("/")) + { + if (!int.TryParse(item, out var month) || month < 1 || month > 12) + { + throw new BusinessException(message: "请输入合法的月份,多个月份请以'/'连接"); + } + } + + rules[row].Months = strValue; + break; + case RuleFactorType.Areas: + if (value.Type is not JTokenType.Integer) + { + throw new BusinessException(message: "分区请传id"); + } + + rules[row].AreaId = int.Parse(strValue); + break; + case RuleFactorType.IsTransit: + if (value.Type is not JTokenType.Boolean) + { + throw new BusinessException(message: "是否中转只接收bool类型"); + } + + rules[row].IsTransit = bool.Parse(strValue); + break; + case RuleFactorType.LeavePort: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "货物类型只接收字符串"); + } + + rules[row].LeavePort = strValue; + break; + case RuleFactorType.ProductCode: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "货物类型只接收字符串"); + } + + rules[row].ProductCode = strValue; + break; + default: + throw new BusinessException(message: $"不支持的因素:{factor.FactorType}"); + } + } + } + } + + public static List MapFactorEntities(List warningFactors) + { + return warningFactors.Select(x => new WarningFactorEntity + { + Type = x.FactorType, + Value = x.FactorValue.ToJson() + }).ToList(); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index 490c7c20..3beac40f 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -15,9 +15,9 @@ namespace SJZY.Track.Application.Services.ForewarningServices; public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency { private IRuleFactorCacheService _ruleFactorCache; - IReadOnlyDictionary> _ruleGroupDict; + IReadOnlyDictionary> _ruleGroupDict; IReadOnlyDictionary> _factorDict; - private IReadOnlyDictionary _rules; + private IReadOnlyDictionary _rules; readonly INotifyService _notifyService; public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService) @@ -88,12 +88,12 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep _rules = null; } - private List DeleteNotifyValue(ForewarningRule rule, int orderId) + private List DeleteNotifyValue(ForewarningRuleItem ruleItem, int orderId) { var members = new List(); - for (var index = 0; index < rule.Count; index++) + for (var index = 0; index < ruleItem.Count; index++) { - var notifyValue = NotifyValue(rule, orderId, index); + var notifyValue = NotifyValue(ruleItem, orderId, index); members.Add(notifyValue); } @@ -105,7 +105,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep /// /// /// - private List GetRule(ForewarningOrderModel order) + private List GetRule(ForewarningOrderModel order) { if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SystemId), out var factors)) { @@ -113,7 +113,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep } var keys = GetForewarningKeys(factors, order); - var result = new List(); + var result = new List(); foreach (var item in keys) { @@ -127,7 +127,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep return result; } - private async ValueTask ExecuteRule(List rules, int orderId) + private async ValueTask ExecuteRule(List rules, int orderId) { var members = new List(); foreach (var rule in rules) @@ -140,16 +140,16 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep return members.Count; } - private List ExecuteRule(ForewarningRule rule, int orderId) + private List ExecuteRule(ForewarningRuleItem ruleItem, int orderId) { var members = new List(); - var intervalMinute = 60 * ((rule.Timeliness - rule.Remind) / rule.Count); // 间隔多少分钟 + var intervalMinute = 60 * ((ruleItem.Timeliness - ruleItem.Remind) / ruleItem.Count); // 间隔多少分钟 - for (var index = 0; index < rule.Count; index++) + for (var index = 0; index < ruleItem.Count; index++) { - var notifyTime = (rule.Remind * 60) + intervalMinute * index; + var notifyTime = (ruleItem.Remind * 60) + intervalMinute * index; var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(notifyTime)); - var notifyValue = new ZMember(NotifyValue(rule, orderId, index), notifyTimestamp); + var notifyValue = new ZMember(NotifyValue(ruleItem, orderId, index), notifyTimestamp); members.Add(notifyValue); } @@ -161,9 +161,9 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); } - private string NotifyValue(ForewarningRule rule, int orderId, int sort) + private string NotifyValue(ForewarningRuleItem ruleItem, int orderId, int sort) { - var result = new RuleNotifyValue(rule.Id, orderId, sort, rule.TrackEnd); + var result = new RuleNotifyValue(ruleItem.Id, orderId, sort, ruleItem.TrackEnd); return result.ToString(); } @@ -220,9 +220,9 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep return rule.Area.HasValue ? rule.Area.Value.ToString() : throw new Exception("区域不能为空"); case RuleFactorType.CargoType: return rule.CargoType; - case RuleFactorType.DeparturePort: + case RuleFactorType.LeavePort: return rule.DeparturePort; - case RuleFactorType.Month: + case RuleFactorType.Months: return rule.Month.HasValue ? rule.Month.Value.ToString() : throw new Exception("月份不能为空"); case RuleFactorType.ProductCode: return rule.ProductCode; diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index 11532104..6a1b011d 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -1,3 +1,5 @@ +using System.ComponentModel.DataAnnotations; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Dtos.Forewarning; @@ -8,110 +10,73 @@ namespace SJZY.Track.Application.Services.ForewarningServices; [Route("/ForewarningService")] public class ForewarningService : ApplicationService { - readonly IRuleRepository _ruleRepository; - readonly IRuleFactorRepository _ruleFactorRepository; - private readonly IRuleItemRepository _ruleItemRepository; - - public ForewarningService(IRuleRepository ruleRepository - , IRuleFactorRepository ruleFactorRepository - , IRuleItemRepository ruleItemRepository) + private readonly IWarningRepository _warningRepository; + + public ForewarningService(IWarningRepository warningRepository) { - _ruleRepository = ruleRepository; - _ruleFactorRepository = ruleFactorRepository; - _ruleItemRepository = ruleItemRepository; + _warningRepository = warningRepository; } /// - /// 创建预警模板,存在则更新 + /// 创建预警 /// /// /// - [HttpPost("ModifyForewarning")] - public async ValueTask ModifyForewarning(CreateRuleFactorRequest input) + [HttpPost("CreateWarning")] + public async Task CreateWarning(CreateWarningInput input) { - var factors = ObjectMapper.Map(input); - var ruleItems = ForewarningFactorHelper.GetFactorItem(factors); - - //todo 原子性没有保证,后续可能需要调整 - if (input.RuleId > 0) - { - await _ruleFactorRepository.DeleteByIdAsync(input.RuleId.ToString()); - } - - if (input.RuleId > 0) - { - var ruleTemplate = await _ruleRepository.GetFirstAsync(val => val.Id == input.RuleId); - if (ruleTemplate == null) - return new UnifyResultDto(false, "规则不存在"); - - ruleTemplate.Name = input.Name; - ruleTemplate.CustomId = input.CustomId; - - await _ruleFactorRepository.IndexDocumentAsync(factors); - await _ruleRepository.UpdateForewarning(ruleTemplate, ruleItems); - return new UnifyResultDto(true, "保存成功"); - } - - var newRuleTemplate = ObjectMapper.Map(input); - var ruleId = await _ruleRepository.CreateForewarning(newRuleTemplate, ruleItems); - factors.Id = ruleId.ToString(); - await _ruleFactorRepository.IndexDocumentAsync(factors); - return new UnifyResultDto(true, "保存成功"); + var warning = ObjectMapper.Map(input); + warning.WarningRules = ForewarningHelper.CalcRuleList(input.TrackStatusSpans, input.WarningFactors); + warning.WarningFactors = ForewarningHelper.MapFactorEntities(input.WarningFactors); + await _warningRepository.CreateForewarningAsync(warning); + return true; } /// - /// 修改时效 + /// 修改预警规则时效 /// - [HttpPost("ModifyTimeliness")] - public async ValueTask ModifyTimeliness(ModifyTimelinessRequest input) + /// + /// + /// + [HttpPost("ModifyTimeSpans")] + public async Task ModifyTimeSpans(ModifyTimeSpanInput input) { - var ruleIds = input.Items.Select(val => val.Id).ToList(); - var ruleCollect = - await _ruleItemRepository.GetListAsync(val => ruleIds.Contains(val.Id) && val.RuleId == input.RuleId); - if (ruleCollect == null || ruleCollect.Count == 0) - throw new BusinessException(message: "规则不存在"); - - var ruleMaps = ruleCollect.ToDictionary(val => val.Id); - var notModifyList = new List(); - foreach (var item in input.Items) + if (!await _warningRepository.IsAnyAsync(x => x.Id == input.WarningId)) { - if (!ruleMaps.TryGetValue(item.Id, out var rule)) - { - notModifyList.Add(item.Id); - continue; - } - - rule.Remind = item.Remind; - rule.Timeliness = item.Timeliness; - rule.Count = item.Count; + throw new BusinessException(message: "预警不存在"); } - await _ruleItemRepository.UpdateRangeAsync(ruleCollect, val => val.RuleId == input.RuleId); + if (input.Items.IsNullOrEmpty()) return false; - if (notModifyList.Count > 0) - return new UnifyResultDto(true, $"更新成功,规则{string.Join(",", notModifyList)}不存在"); + var warningRules = ObjectMapper.Map, List>(input.Items); - return new UnifyResultDto(true, "更新成功"); + await _warningRepository.ModifyTimeSpansAsync(warningRules); + + return true; + } + + + /// + /// 获取预警分页列表 + /// + /// + /// + [HttpPost("GetWarningPageList")] + public async Task> GetWarningPageList(GetWarningPageInputVo inputVo) + { + if (!inputVo.KeyWord.IsNullOrEmpty()) inputVo.KeyWord = inputVo.KeyWord!.Trim(); + return await _warningRepository.GetWarningPageListAsync(inputVo); } /// /// 查询预警规则列表 /// + /// 预警规则id /// - [HttpPost("QueryForewarning")] - public async Task QueryForewarning(QueryForewarningRequest input) + [HttpGet("GetWarningRuleList")] + public async Task> GetWarningRuleListAsync([Required] int warningId) { - var result = await _ruleRepository.QueryForewarningRuleAsync(input); - return new UnifyResultDto(true, result); - } - - /// - /// 查询预警规则明细列表 - /// - [HttpPost("QueryForewarningRules")] - public async Task> QueryForewarningRuleItems(QueryForewarningRuleRequest input) - { - return await _ruleItemRepository.QueryForewarningRuleItemsAsync(input); + return await _warningRepository.GetWarningRuleListAsync(warningId); } /// diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs deleted file mode 100644 index 74bc9345..00000000 --- a/src/SJZY.Track.Application/Services/ForewarningServices/RuleFactorCacheService.cs +++ /dev/null @@ -1,194 +0,0 @@ -using SJZY.Expand.ABP.Core; -using SJZY.Track.Application.Contract.Services; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Dtos.Forewarning; -using Volo.Abp.DependencyInjection; - -namespace SJZY.Track.Application.Services.ForewarningServices; - -public class RuleFactorCacheService : IRuleFactorCacheService, ITransientDependency -{ - private const string GlobalFactorLockKey = "RuleFactorCacheService_GlobalLock"; - private const string GlobalRuleLockKey = "RuleFactorCacheService_GlobalLock"; - readonly IRuleFactorRepository _ruleFactorRepository; - readonly IRuleItemRepository _ruleItemRepository; - readonly IRuleRepository _ruleRepository; - - public RuleFactorCacheService(IRuleFactorRepository ruleFactorRepository, - IRuleItemRepository ruleItemRepository, IRuleRepository ruleRepository) - { - _ruleFactorRepository = ruleFactorRepository; - _ruleItemRepository = ruleItemRepository; - _ruleRepository = ruleRepository; - } - - private string GetKey() - { - return $"{GlobalConst.RuleFactorKeyPrefix}:allFactor"; - } - - private string GetRuleKey() - { - return $"{GlobalConst.RuleFactorKeyPrefix}:allRule"; - } - - /// - /// 获取所有规则数据 - /// - /// - [NonAction] - public async Task GetAllFactorCollect() - { - var key = GetRuleKey(); - var result = await RedisHelper.Client.GetAsync(key); - if (result == null) - { - using (var globalLock = RedisHelper.Client.Lock(GlobalRuleLockKey, 10)) - { - result = await RedisHelper.Client.GetAsync(key); - if (result != null) return result; - - var ruleCollect = await _ruleItemRepository.GetListAsync(val => true); - if (ruleCollect == null || ruleCollect.Count == 0) - { - ForewarningRule[] rules = new ForewarningRule[0]; - await RedisHelper.Client.SetAsync(key, rules, TimeSpan.FromSeconds(20)); - return result; - } - - var ruleList = ruleCollect.SelectMany(RuleEntityToRule); - await RedisHelper.Client.SetAsync(key, ruleList); - return result; - } - } - - return result; - } - - /// - /// 获取所有因素数据 - /// - /// 获取所有因素,返回值可能为空 - [NonAction] - public async Task> GetAllRuleFactor() - { - var key = GetKey(); - var result = await RedisHelper.Client.GetAsync>(key); - if (result == null) - { - using (var globalLock = RedisHelper.Client.Lock(GlobalFactorLockKey, 10)) - { - result = await RedisHelper.Client.GetAsync>(key); - if (result != null) return result; - - result = await GenerateAllRuleFactor(); - if (result == null || result.Count == 0) - { - await RedisHelper.Client.SetAsync(key, new List(), TimeSpan.FromSeconds(20)); - return result; - } - - await RedisHelper.Client.SetAsync(key, result); - return result; - } - } - - return result; - } - - [NonAction] - public void ClearFactorCache() - { - RedisHelper.Client.DelAsync(GetKey()); - } - - [NonAction] - public void ClearRuleCache() - { - RedisHelper.Client.DelAsync(GetRuleKey()); - } - - private async Task> GenerateAllRuleFactor() - { - var factors = await _ruleFactorRepository.GetAllList(); - var ruleTemplate = await _ruleRepository.GetListAsync(val => true); - var ruleMap = ruleTemplate.ToDictionary(val => val.Id); - var result = new List(); - foreach (var item in factors) - { - if (!ruleMap.TryGetValue(item.RuleId, out var rule)) - continue; - var ruleFactors = EntityToRuleFactor(item, rule); - result.AddRange(ruleFactors); - } - - return result; - } - - private ForewarningRule[] RuleEntityToRule(RuleItemEntity entity) - { - var result = RuleCollectToRule(entity); - if (string.IsNullOrEmpty(entity.Month)) - { - return new ForewarningRule[] { result }; - } - - var months = entity.Month.Split('/'); - var rules = new List(months.Length); - - foreach (var month in months) - { - if (int.TryParse(month, out int monthInt)) - { - var rule = result; - rule.Month = monthInt; - rules.Add(rule); - } - } - - return rules.ToArray(); - } - - private ForewarningRule RuleCollectToRule(RuleItemEntity entity) - { - return new ForewarningRule - { - Id = entity.Id, - RuleId = entity.RuleId, - Remind = entity.Remind, - Timeliness = entity.Timeliness, - Count = entity.Count, - TrackStart = entity.TrackStart, - TrackEnd = entity.TrackEnd, - CargoType = entity.CargoType, - Month = null, - Area = entity.Area, - IsTransit = entity.IsTransit, - DeparturePort = entity.DeparturePort, - ProductCode = entity.ProductCode - }; - } - - private List EntityToRuleFactor(RuleFactorEntity entity, RuleEntity ruleTemplate) - { - List result = new List(); - foreach (var track in entity.Tracks) - { - var item = new RuleFactor() - { - CustomerId = ruleTemplate.CustomId, - RuleId = ruleTemplate.Id, - NotifyUser = track.NotifyUser, - NotifyTemplate = track.NotifyTemplate, - FactorItems = entity.FactorItems, - End = track.End, - Start = track.Start, - SystemId = ruleTemplate.SubSystemId - }; - result.Add(item); - } - - return result; - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs index 0b3fe50a..cc5cd662 100644 --- a/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs +++ b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs @@ -3,31 +3,16 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Application.Validations.Forewarning; -public class CreateRuleFactorValidation : AbstractValidator +public class CreateRuleFactorValidation : AbstractValidator { public CreateRuleFactorValidation() { - RuleForEach(x => x.Tracks).SetValidator(new RuleTrackStateDtoValidator()); - RuleFor(x => x.FactorItems).NotNull().WithMessage("FactorItems cannot be null."); + RuleFor(x => x.WarningFactors).NotNull().WithMessage("因素列表不能为空"); + RuleFor(x => x.TrackStatusSpans).NotNull().WithMessage("轨迹状态列表不能为空"); - RuleFor(x => x.CargoTypes).NotEmpty().WithMessage("CargoTypes cannot be empty."); - RuleForEach(x => x.CargoTypes).NotEmpty().WithMessage("CargoType cannot be empty."); - - RuleFor(x => x.Months).NotEmpty().WithMessage("Months cannot be empty."); - RuleForEach(x => x.Months) - .ForEach(val=>val.Must(t=>t>0)) - .WithMessage("Each month array must have 12 elements."); - - RuleFor(x => x.IsTransit).NotEmpty().WithMessage("IsTransit cannot be empty."); - RuleForEach(x => x.IsTransit).InclusiveBetween(0, 1).WithMessage("IsTransit must be 0 or 1."); - - RuleFor(x => x.Areas).NotEmpty().WithMessage("Areas cannot be empty."); - RuleForEach(x => x.Areas).GreaterThan(0).WithMessage("Area must be greater than 0."); - - RuleFor(x => x.DeparturePorts).NotEmpty().WithMessage("DeparturePorts cannot be empty."); - RuleForEach(x => x.DeparturePorts).NotEmpty().WithMessage("DeparturePort cannot be empty."); - - RuleFor(x => x.ProductCodes).NotEmpty().WithMessage("ProductCodes cannot be empty."); - RuleForEach(x => x.ProductCodes).NotEmpty().WithMessage("ProductCode cannot be empty."); + RuleFor(x => x.NotifyTemplate).NotEmpty().WithMessage("通知模板必填") + .MaximumLength(256).WithMessage("通知模板长度不能超过256"); + + // todo: more validation } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs index 6de8c9b6..7dab2f60 100644 --- a/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs +++ b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs @@ -3,13 +3,12 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Application.Validations.Forewarning; -public class RuleTrackStateDtoValidator : AbstractValidator +public class RuleTrackStateDtoValidator : AbstractValidator { public RuleTrackStateDtoValidator() { - RuleFor(x => x.Start).GreaterThanOrEqualTo(0).WithMessage("Start must be greater than or equal to 0."); - RuleFor(x => x.End).GreaterThanOrEqualTo(0).WithMessage("End must be greater than or equal to 0."); - RuleFor(x => x.NotifyUser).NotEmpty().WithMessage("NotifyUser cannot be empty."); - RuleFor(x => x.NotifyTemplate).NotEmpty().WithMessage("NotifyTemplate cannot be empty."); + RuleFor(x => x.StartTrackStatusId).GreaterThan(0).WithMessage("起始轨迹状态id必须大于0"); + RuleFor(x => x.EndTrackStatusId).GreaterThan(0).WithMessage("终止轨迹状态id必须大于0"); + RuleFor(x => x.NotifyUserId).NotEmpty().WithMessage("通知对象不能为空"); } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs deleted file mode 100644 index ae0406fe..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IForewarningList.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -public interface IForewarningList -{ - void AddForewarning(int score,int id); - - void DeleteForewarning(int score,int id); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs deleted file mode 100644 index 38b32ef7..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleFactorRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SJZY.Expand.ElasticSearch.Services; - -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -public interface IRuleFactorRepository:IElasticsearchClientService -{ - Task> GetFactorByIdsAsync(int[] ruleIds); - - Task> GetAllList(); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs deleted file mode 100644 index c06aa847..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleItemRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using SJZY.Track.Domain.Dtos.Forewarning; - -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -public interface IRuleItemRepository : IBasicRepository -{ - /// - /// 查询分页 - /// - /// - /// - Task> QueryForewarningRuleItemsAsync(QueryForewarningRuleRequest input); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs deleted file mode 100644 index 04488ef5..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IRuleRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SJZY.Track.Domain.Dtos.Forewarning; - -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -public interface IRuleRepository : IBasicRepository -{ - Task CreateForewarning(RuleEntity rule, RuleItemEntity[] ruleItems); - - Task UpdateForewarning(RuleEntity rule, RuleItemEntity[] factorList); - - Task> QueryForewarningRuleAsync(QueryForewarningRequest input); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs new file mode 100644 index 00000000..b3f6bd97 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs @@ -0,0 +1,48 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IWarningRepository : IBasicRepository +{ + /// + /// 创建预警 + /// + /// + /// + Task CreateForewarningAsync(WarningEntity warning); + + /// + /// 修改预警 + /// + /// + /// + Task UpdateForewarningAsync(WarningEntity warning); + + /// + /// 复制预警 + /// + /// + /// + Task CopyForewarning(int warningId); + + /// + /// 获取预警分页列表 + /// + /// + /// + Task> GetWarningPageListAsync(GetWarningPageInputVo input); + + /// + /// 获取预警规则列表 + /// + /// 预警id + /// + Task> GetWarningRuleListAsync(int warningId); + + /// + /// 修改预警时效 + /// + /// + /// + Task ModifyTimeSpansAsync(List inputItems); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs deleted file mode 100644 index 15439fbf..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleEntity.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -[SugarTable("t_rule")] -public class RuleEntity:IAggregateRoot -{ - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 子系统id - /// - [SugarColumn(ColumnName = "SubSystemId")] - public int SubSystemId { get; set; } - - /// - /// 客户id - /// - [SugarColumn(ColumnName = "CustomId")] - public int CustomId { get; set; } - - /// - /// 规则模板名称,KPI名称 - /// - [SugarColumn(ColumnName = "Name", Length = 64)] - public string Name { get; set; } - - /// - /// 规则模板名称,KPI名称 - /// - [SugarColumn(ColumnName = "CustomName", Length = 64)] - public string CustomName { get; set; } - - /// - /// 创建人 - /// - [SugarColumn(ColumnName = "CreateUserId")] - public int CreateUserId { get; set; } - - /// - /// 创建时间 - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 更新人 - /// - [SugarColumn(ColumnName = "UpdateUserId", IsNullable = false)] - public int UpdateUserId { get; set; } - - /// - /// 更新时间 - /// - [SugarColumn(ColumnName = "UpdateTime", IsNullable = false)] - public DateTime UpdateTime { get; set; } - -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs deleted file mode 100644 index 0b99b712..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleFactorEntity.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Nest; -using SJZY.Expand.ElasticSearch; -using SJZY.Track.Domain.Consts; - -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -[ElasticsearchType(RelationName = GlobalConst.RuleFactorIndex)] -public class RuleFactorEntity : IdBaseIndex -{ - /// - /// RuleId 表的id - /// - [Keyword(Index = true)] - public int RuleId { get; set; } - - /// - /// 获取或设置规则跟踪状态实体的列表。 - /// - public List Tracks { get; set; } - - /// - /// 获取或设置因素项模型的列表。 - /// - public List FactorItems { get; set; } - - /// - /// 获取或设置货物类型的列表。 - /// - public List CargoTypes { get; set; } - - /// - /// 获取或设置月份的列表。 - /// - public List Months { get; set; } - - /// - /// 获取或设置是否中转的列表。 - /// - public List IsTransit { get; set; } - - /// - /// 获取或设置区域的列表。 - /// - public List Areas { get; set; } - - /// - /// 获取或设置起运港口的列表。 - /// - public List DeparturePorts { get; set; } - - /// - /// 获取或设置产品编号的列表。 - /// - public List ProductCodes { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs deleted file mode 100644 index b08b1edc..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleItemEntity.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -[SugarTable("t_rule_item")] -public class RuleItemEntity : IAggregateRoot, ICloneable -{ - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - [SugarColumn(ColumnName = "RuleId")] public int RuleId { get; set; } - - /// - /// 提醒的时间(小时) - /// - [SugarColumn(ColumnName = "Remind")] - public float Remind { get; set; } - - /// - /// 时效(小时) - /// - [SugarColumn(ColumnName = "Timeliness")] - public float Timeliness { get; set; } - - /// - /// 提醒次数 - /// - [SugarColumn(ColumnName = "Count")] - public int Count { get; set; } - - /// - /// 起始轨迹 - /// - [SugarColumn(ColumnName = "TrackStart", IsNullable = false)] - public int TrackStart { get; set; } - - /// - /// 终止轨迹 - /// - [SugarColumn(ColumnName = "TrackEnd", IsNullable = false)] - public int TrackEnd { get; set; } - - /// - /// 货物类型 - /// - [SugarColumn(ColumnName = "CargoType", Length = 64)] - public string CargoType { get; set; } - - /// - /// 月份 - /// - [SugarColumn(ColumnName = "Month", Length = 25)] - public string Month { get; set; } - - /// - /// 区域 - /// - [SugarColumn(ColumnName = "Area")] - public int? Area { get; set; } - - /// - /// 是否中转 - /// - [SugarColumn(ColumnName = "IsTransit")] - public bool? IsTransit { get; set; } - - /// - /// 起运港口 - /// - [SugarColumn(ColumnName = "DeparturePort")] - public string DeparturePort { get; set; } - - /// - /// 产品编码 - /// - [SugarColumn(ColumnName = "ProductCode")] - public string ProductCode { get; set; } - - /// - /// 创建人 - /// - [SugarColumn(ColumnName = "CreateUserId")] - public int CreateUserId { get; set; } - - /// - /// 创建时间 - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 更新人 - /// - [SugarColumn(ColumnName = "UpdateUserId")] - public int UpdateUserId { get; set; } - - /// - /// 更新时间 - /// - [SugarColumn(ColumnName = "UpdateTime")] - public DateTime UpdateTime { get; set; } - - public object Clone() - { - var clone = this.MemberwiseClone(); - return clone; - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs deleted file mode 100644 index 554d1e2c..00000000 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/RuleTrackStateModel.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -public class RuleTrackStateModel -{ - /// - /// Gets or sets the start track value. - /// - public int Start { get; set; } - - /// - /// Gets or sets the end track value. - /// - public int End { get; set; } - - /// - /// Gets or sets the user to notify. - /// - public string NotifyUser { get; set; } - - /// - /// Gets or sets the notification template. - /// - public string NotifyTemplate { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs new file mode 100644 index 00000000..b713ffe0 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs @@ -0,0 +1,53 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_warning")] +public class WarningEntity: IFullAuditedBasicEntitys, IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId")] + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + [SugarColumn(ColumnName = "CustomerId")] + public int CustomerId { get; set; } + + /// + /// 客户 + /// + [SugarColumn(ColumnName = "CustomerName", Length = 255)] + public string CustomerName { get; set; } = null!; + + /// + /// 规则模板名称,KPI名称 + /// + [SugarColumn(ColumnName = "Name", Length = 64)] + public string Name { get; set; } = null!; + + /// + /// 是否启用,默认否 + /// + [SugarColumn(ColumnName = "IsEnable")] + public bool IsEnable { get; set; } + + /// + /// 预警规则 + /// + [SugarColumn(IsIgnore = true)] + public List WarningRules { get; set; } = new(); + + /// + /// 预警因素 + /// + [SugarColumn(IsIgnore = true)] + public List WarningFactors { get; set; } = new(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs new file mode 100644 index 00000000..62a37538 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs @@ -0,0 +1,30 @@ +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public class WarningFactorEntity : IFullAuditedBasicEntitys +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 预警id + /// + [SugarColumn(ColumnName = "WarningId")] + public int WarningId { get; set; } + + /// + /// 因素类型(1货物类型,2月份,3分区,4是否中转,5起运港口,6销售产品) + /// + [SugarColumn(ColumnName = "Type")] + public RuleFactorType Type { get; set; } + + /// + /// 预警因素值(json数组字符串) + /// + [SugarColumn(ColumnName = "Value")] + public string Value { get; set; } = null!; +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs new file mode 100644 index 00000000..ce26f2a1 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs @@ -0,0 +1,83 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_warning_rule")] +public class WarningRuleEntity : IFullAuditedBasicEntitys +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 预警id + /// + [SugarColumn(ColumnName = "WarningId")] + public int WarningId { get; set; } + + /// + /// 时效(小时) + /// + [SugarColumn(ColumnName = "TotalTimeSpan")] + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) + /// + [SugarColumn(ColumnName = "WarnTimeSpan")] + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + [SugarColumn(ColumnName = "WarnCount")] + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态id + /// + [SugarColumn(ColumnName = "StartTrackStatusId", IsNullable = false)] + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + [SugarColumn(ColumnName = "EndTrackStatusId", IsNullable = false)] + public int EndTrackStatusId { get; set; } + + /// + /// 货物类型 + /// + [SugarColumn(ColumnName = "CargoType", Length = 64)] + public string? CargoType { get; set; } + + /// + /// 月份 + /// + [SugarColumn(ColumnName = "Months", Length = 25)] + public string? Months { get; set; } + + /// + /// 区域 + /// + [SugarColumn(ColumnName = "AreaId")] + public int? AreaId { get; set; } + + /// + /// 是否中转 + /// + [SugarColumn(ColumnName = "IsTransit")] + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + [SugarColumn(ColumnName = "LeavePort")] + public string? LeavePort { get; set; } + + /// + /// 产品编码 + /// + [SugarColumn(ColumnName = "ProductCode")] + public string? ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs index 68199b0f..0226853e 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs @@ -1,16 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using SJZY.Track.Domain.Enums; + namespace SJZY.Track.Domain.Dtos.Forewarning { - public class CreateRuleFactorRequest + public class CreateWarningInput { - /// - /// RuleId 表的id,小于0 表示创建新的规则 - /// - public int RuleId { get; set; } - /// /// 模板名称 /// - public string Name { get; set; } + public string Name { get; set; } = null!; /// /// 子系统id @@ -20,46 +18,31 @@ namespace SJZY.Track.Domain.Dtos.Forewarning /// /// 客户id /// - public int CustomId { get; set; } + public int CustomerId { get; set; } /// - /// 获取或设置规则跟踪状态实体的列表。 + /// 客户名称 /// - public List Tracks { get; set; } + public string CustomerName { get; set; } = null!; /// - /// 获取或设置因素项模型的列表。 + /// 通知方式 /// - public List FactorItems { get; set; } + public NotifyMode NotifyMode { get; set; } /// - /// 获取或设置货物类型的列表。 + /// 通知模板 /// - public List CargoTypes { get; set; } + public string NotifyTemplate { get; set; } = null!; /// - /// 获取或设置月份的列表。 + /// 轨迹状态跨度列表 /// - public List Months { get; set; } + public List TrackStatusSpans { get; set; } = new(); /// - /// 获取或设置是否中转的列表。 + /// 预警因素列表。 /// - public List IsTransit { get; set; } - - /// - /// 获取或设置区域的列表。 - /// - public List Areas { get; set; } - - /// - /// 获取或设置起运港口的列表。 - /// - public List DeparturePorts { get; set; } - - /// - /// 获取或设置产品编号的列表。 - /// - public List ProductCodes { get; set; } + public List WarningFactors { get; set; } = new(); } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs deleted file mode 100644 index 9360d491..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/FactorItemDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -using SJZY.Track.Domain.Enums; - -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class FactorItemDto -{ - /// - /// Gets or sets the sort order. - /// - public int Sort { get; set; } - - /// - /// Gets or sets the type of the rule factor. - /// - public RuleFactorType FactorType { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs similarity index 91% rename from src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs rename to src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs index b8499e64..ef550296 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRule.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; -public record struct ForewarningRule:IForewarningFactorValue +public record struct ForewarningRuleItem:IForewarningFactorValue { public int Id { get; set; } diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs new file mode 100644 index 00000000..08d0b0ea --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetWarningPageInputVo: PageInfoInput +{ + /// + /// 子系统id + /// + public int? SystemId { get; set; } + + /// + /// 关键字(客户or名称) + /// + public string? KeyWord { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningRuleListInput.cs similarity index 87% rename from src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs rename to src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningRuleListInput.cs index 0014a95a..72b951be 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRuleRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningRuleListInput.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; -public class QueryForewarningRuleRequest: PageInfoInput +public class GetWarningRuleListInput: PageInfoInput { /// /// kpi 预警规则模板id diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs deleted file mode 100644 index 841292f7..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ModifyTimelinessRequest.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class ModifyTimelinessRequest -{ - /// - /// 规则详情中的时效相关信息 - /// - public List Items { get; set; } - - /// - /// 规则模板id - /// - public int RuleId { get; set; } -} - -/// -/// 规则详情时效 -/// -public class TimelinessDto -{ - /// - /// 时效 - /// - public float Timeliness { get; set; } - - /// - /// 提醒时效 - /// - public float Remind { get; set; } - - /// - /// 提醒次数 - /// - public int Count { get; set; } - - /// - /// 规则详情id - /// - public int Id { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs deleted file mode 100644 index 5bb9fea1..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryForewarningRequest.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class QueryForewarningRequest: PageInfoInput -{ - /// - /// 子系统id - /// - public int? SystemId { get; set; } - - /// - /// 客户或者模板名称 - /// - public string? KeyWord { get; set; } - - /// - /// 排序方式,不填不排序 - /// - public string? SortField { get; set; } - - /// - /// 排序方式 - /// - public bool IsAsc { get; set; } = false; -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs deleted file mode 100644 index 4cce0e58..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectDto.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class RuleCollectDto -{ - public int Id { get; set; } - public int RuleId { get; set; } - public float Remind { get; set; } - public float Timeliness { get; set; } - public int Count { get; set; } - public int TrackStart { get; set; } - public int TrackEnd { get; set; } - public string CargoType { get; set; } - public string Month { get; set; } - public int? Area { get; set; } - public bool? IsTransit { get; set; } - public string DeparturePort { get; set; } - public string ProductCode { get; set; } - public int CreateUserId { get; set; } - public DateTime CreateTime { get; set; } - public int UpdateUserId { get; set; } - public DateTime UpdateTime { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs deleted file mode 100644 index 93644080..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleInfoModel.cs +++ /dev/null @@ -1,42 +0,0 @@ -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; -using SJZY.Track.Domain.Enums; - -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class RuleInfoModel -{ - /// - /// 获取或设置因素项模型的列表。 - /// - public FactorItemModel FactorItems { get; set; } - - /// - /// 获取或设置货物类型的列表。 - /// - public string CargoTypes { get; set; } - - /// - /// 获取或设置月份的列表。 - /// - public short Months { get; set; } - - /// - /// 获取或设置是否中转的列表。 - /// - public bool? IsTransit { get; set; } - - /// - /// 获取或设置区域的列表。 - /// - public int Areas { get; set; } - - /// - /// 获取或设置起运港口的列表。 - /// - public string DeparturePorts { get; set; } - - /// - /// 获取或设置产品编号的列表。 - /// - public string ProductCodes { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs deleted file mode 100644 index 52abd1fa..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleTrackStateDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class RuleTrackStateDto -{ - /// - /// Gets or sets the start track value. - /// - public int Start { get; set; } - - /// - /// Gets or sets the end track value. - /// - public int End { get; set; } - - /// - /// Gets or sets the user to notify. - /// - public string NotifyUser { get; set; } - - /// - /// Gets or sets the notification template. - /// - public string NotifyTemplate { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs new file mode 100644 index 00000000..f9eda466 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class TrackStatusSpanDto +{ + /// + /// 起始轨迹状态id + /// + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + public int EndTrackStatusId { get; set; } + + /// + /// 通知人id + /// + public int NotifyUserId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningFactorDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningFactorDto.cs new file mode 100644 index 00000000..3d4e93b9 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningFactorDto.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json.Linq; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningFactorDto +{ + /// + /// 因素类型 + /// + public RuleFactorType FactorType { get; set; } + + /// + /// 因素值 + /// + public JArray FactorValue { get; set; } = new(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs new file mode 100644 index 00000000..58408422 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningPageOutput +{ + /// + /// 预警id + /// + public int Id { get; set; } + + /// + /// 子系统 + /// + public string SubSystem { get; set; } = null!; + + /// + /// 客户 + /// + public string Custom { get; set; } = null!; + + /// + /// 规则模板名称,KPI名称 + /// + public string Name { get; set; } = null!; + + /// + /// 更新时间 + /// + public DateTime? UpdateTime { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs new file mode 100644 index 00000000..c614eb38 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs @@ -0,0 +1,64 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningRuleOutput +{ + /// + /// 自增主键 + /// + public int Id { get; set; } + + /// + /// 时效(小时) + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态 + /// + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态 + /// + public string EndTrackStatus { get; set; } = null!; + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 月份 + /// + public string? Months { get; set; } + + /// + /// 区域 + /// + public int? AreaId { get; set; } + + /// + /// 是否中转 + /// + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + public string? LeavePort { get; set; } + + /// + /// 销售产品 + /// + public string? ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs b/src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs deleted file mode 100644 index 082b245a..00000000 --- a/src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SJZY.Track.Domain.Dtos.Order -{ - public class GetOrderDetailsInputVO - { - - } - - public class TrackOrderDetailVO - { - - } -} diff --git a/src/SJZY.Track.Domain/Enums/NotifyMode.cs b/src/SJZY.Track.Domain/Enums/NotifyMode.cs new file mode 100644 index 00000000..f5821903 --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/NotifyMode.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Enums; + +public enum NotifyMode +{ + /// + /// 站内信 + /// + SiteInternal = 1, + + /// + /// 飞书 + /// + FeiShu = 2 +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Enums/RuleFactorType.cs b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs index 64d32839..5ff3e3e5 100644 --- a/src/SJZY.Track.Domain/Enums/RuleFactorType.cs +++ b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs @@ -9,12 +9,12 @@ public enum RuleFactorType /// /// 表示货物类型。 /// - CargoType, + CargoType = 1, /// /// 表示月份。 /// - Month, + Months, /// /// 表示分区或区域。 @@ -29,10 +29,10 @@ public enum RuleFactorType /// /// 表示起运港口。 /// - DeparturePort, + LeavePort, /// - /// 表示产品编号。 + /// 表示销售产品。 /// ProductCode } \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index 85faff5d..8a0fcd0e 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -91,7 +91,7 @@ AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;"); public async Task UnLinkByIdsAsync(List linkIds) { - await Context.Deleteable(linkIds).ExecuteCommandAsync(); + await Context.Deleteable(linkIds).ExecuteCommandAsync(); } #endregion diff --git a/src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs deleted file mode 100644 index b9492f28..00000000 --- a/src/SJZY.Track.Repository/Repositories/RuleFactorRepository.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Nest; -using SJZY.Expand.ElasticSearch.Services; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; - -namespace SJZY.Track.Repository.Repositories; - -public class RuleFactorRepository:ElasticSearchContextAbstract, IRuleFactorRepository, - ITransientDependency -{ - public RuleFactorRepository(ConnectionFactory connectionFactory) : base(connectionFactory) - { - } - - public async Task CreateAsync(RuleFactorEntity entity) - { - await IndexDocumentAsync(entity); - } - - public async Task> GetFactorByIdsAsync(int[] ruleIds) - { - var response = await Context.SearchAsync(s => s.Query(q => q.Terms(t => t.Field(f => f.RuleId).Terms(ruleIds)))); - int num = response.ApiCall.HttpStatusCode ?? throw new Exception("数据查询失败,原因:" + response.DebugInformation); - switch (num) - { - case 200: - return response.Documents.ToList(); - case 404: - return new List(); - default: - throw new Exception($"数据查询失败,http status: {num},原因:{response.DebugInformation}"); - } - } - - /// - /// 获取所有数据 - /// - /// - /// - public async Task> GetAllList() - { - var response = await Context.SearchAsync(); - int num = response.ApiCall.HttpStatusCode ?? throw new Exception("数据查询失败,原因:" + response.DebugInformation); - switch (num) - { - case 200: - return response.Documents.ToList(); - case 404: - return new List(); - default: - throw new Exception($"数据查询失败,http status: {num},原因:{response.DebugInformation}"); - } - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs deleted file mode 100644 index 03139fb6..00000000 --- a/src/SJZY.Track.Repository/Repositories/RuleItemRepository.cs +++ /dev/null @@ -1,50 +0,0 @@ -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; -using SJZY.Track.Domain.Dtos.Forewarning; - -namespace SJZY.Track.Repository.Repositories; - -public class RuleItemRepository : BasicRepository, IRuleItemRepository, ITransientDependency -{ - /// - /// 查询预警规则分页信息 - /// - /// - /// - public Task> QueryForewarningRuleItemsAsync(QueryForewarningRuleRequest input) - { - var query = Context.Queryable() - .Where(val => val.RuleId == input.RuleId); - - if (!string.IsNullOrEmpty(input.SortField)) - { - query = query.OrderByPropertyName(input.SortField, input.IsAsc ? OrderByType.Asc : OrderByType.Desc); - } - - return query.Select(val => MapToDto(val)) - .ToPagedListAsync(input.PageIndex, input.PageSize); - } - - private RuleCollectDto MapToDto(RuleItemEntity entity) - { - return new RuleCollectDto() - { - Id = entity.Id, - RuleId = entity.RuleId, - Remind = entity.Remind, - Timeliness = entity.Timeliness, - Count = entity.Count, - TrackStart = entity.TrackStart, - TrackEnd = entity.TrackEnd, - CargoType = entity.CargoType, - Month = entity.Month, - Area = entity.Area, - IsTransit = entity.IsTransit, - DeparturePort = entity.DeparturePort, - ProductCode = entity.ProductCode, - CreateUserId = entity.CreateUserId, - CreateTime = entity.CreateTime, - UpdateUserId = entity.UpdateUserId, - UpdateTime = entity.UpdateTime - }; - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/RuleRepository.cs b/src/SJZY.Track.Repository/Repositories/RuleRepository.cs deleted file mode 100644 index a285017a..00000000 --- a/src/SJZY.Track.Repository/Repositories/RuleRepository.cs +++ /dev/null @@ -1,52 +0,0 @@ -using SJZY.Track.Domain; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; -using SJZY.Track.Domain.Dtos.Forewarning; - -namespace SJZY.Track.Repository.Repositories; - -public class RuleRepository : BasicRepository, IRuleRepository, ITransientDependency -{ - public async Task CreateForewarning(RuleEntity rule, RuleItemEntity[] ruleItems) - { - using var tran = TransactionHelper.GetReadCommitted(); - - var ruleId = await InsertReturnIdentityAsync(rule); - foreach (var item in ruleItems) - { - item.RuleId = ruleId; - } - - await Context.Insertable(ruleItems).ExecuteCommandAsync(); - tran.Complete(); - return ruleId; - } - - public async Task UpdateForewarning(RuleEntity rule, RuleItemEntity[] factorList) - { - using var tran = TransactionHelper.GetReadCommitted(); - await UpdateAsync(rule); - await Context.Deleteable().Where(x => x.RuleId == rule.Id).ExecuteCommandAsync(); - await Context.Insertable(factorList).ExecuteCommandAsync(); - tran.Complete(); - } - - /// - /// 查询预警模板分页信息 - /// - /// - /// - public Task> QueryForewarningRuleAsync(QueryForewarningRequest input) - { - var query = Context.Queryable() - .WhereIF(input.SystemId.HasValue, val => val.SubSystemId == input.SystemId) - .WhereIF(!string.IsNullOrEmpty(input.KeyWord), - val => val.CustomName.Contains(input.KeyWord!) || val.Name.Contains(input.KeyWord!)); - - if (!string.IsNullOrEmpty(input.SortField)) - { - query = query.OrderByPropertyName(input.SortField, input.IsAsc ? OrderByType.Asc : OrderByType.Desc); - } - - return query.ToPagedListAsync(input.PageIndex, input.PageSize); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs new file mode 100644 index 00000000..81c704ac --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs @@ -0,0 +1,75 @@ +using SJZY.Track.Domain; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Repositories; + +public class WarningRepository : BasicRepository, IWarningRepository, ITransientDependency +{ + public async Task CreateForewarningAsync(WarningEntity warning) + { + using var tran = TransactionHelper.GetReadCommitted(); + + var ruleId = await InsertReturnIdentityAsync(warning); + warning.WarningRules.ForEach(x => x.WarningId = ruleId); + warning.WarningFactors.ForEach(x => x.WarningId = ruleId); + + await Context.Insertable(warning.WarningRules).ExecuteCommandAsync(); + await Context.Insertable(warning.WarningFactors).ExecuteCommandAsync(); + tran.Complete(); + return ruleId; + } + + public Task UpdateForewarningAsync(WarningEntity warning) + { + throw new NotImplementedException(); + } + + public Task CopyForewarning(int warningId) + { + throw new NotImplementedException(); + } + + public Task> GetWarningPageListAsync(GetWarningPageInputVo input) + { + var query = Context.Queryable() + .LeftJoin((a, b) => a.SubSystemId == b.Id) + .WhereIF(input.SystemId.HasValue, (a, b) => a.SubSystemId == input.SystemId) + .WhereIF(!string.IsNullOrEmpty(input.KeyWord), a => a.CustomerName.Contains(input.KeyWord!) || a.Name.Contains(input.KeyWord!)) + .OrderBy(a => a.UpdateTime, OrderByType.Desc); + + return query + .Select((a, b) => new WarningPageOutput + { + Id = a.Id, + SubSystem = b.CnName, + Custom = a.CustomerName, + Name = a.Name, + UpdateTime = a.UpdateTime + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + + public async Task> GetWarningRuleListAsync(int warningId) + { + return await Context.Queryable() + .LeftJoin((a, b) => a.StartTrackStatusId == b.Id) + .LeftJoin((a, b, c) => a.EndTrackStatusId == c.Id) + .Where(a => a.WarningId == warningId) + .Select((a, b, c) => new WarningRuleOutput + { + StartTrackStatus = b.Status, + EndTrackStatus = c.Status, + }, true) + .ToListAsync(); + } + + public async Task ModifyTimeSpansAsync(List rules) + { + return await Context.Updateable(rules) + .UpdateColumns(x => new { x.TotalTimeSpan, x.WarnTimeSpan, x.WarnCount }) + .ExecuteCommandAsync(); + } +} \ No newline at end of file From 24e95d7fadf67470d14c2f243184f462af133be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 10:24:20 +0800 Subject: [PATCH 25/60] =?UTF-8?q?feat=EF=BC=9A=20=E8=BD=A8=E8=BF=B9?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E7=95=8C=E9=9D=A2=E7=9A=84=E6=8B=89=E5=8F=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=B0=86=E2=80=9C=E8=BD=A8=E8=BF=B9=E6=97=B6?= =?UTF-8?q?=E5=8C=BA=E2=80=9D=E6=94=B9=E6=88=90=E2=80=9C=E5=85=9C=E5=BA=95?= =?UTF-8?q?=E8=BD=A8=E8=BF=B9=E6=97=B6=E5=8C=BA=E2=80=9D=EF=BC=8C=E2=80=9C?= =?UTF-8?q?=E8=BD=A8=E8=BF=B9=E5=8F=91=E7=94=9F=E5=9C=B0=E2=80=9D=E6=94=B9?= =?UTF-8?q?=E6=88=90=E2=80=9C=E5=85=9C=E5=BA=95=E8=BD=A8=E8=BF=B9=E5=8F=91?= =?UTF-8?q?=E7=94=9F=E5=9C=B0=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrackPull/EditTrackPullContentInput.cs | 6 + .../TrackPull/TrackPullContentConfigDto.cs | 10 +- .../PullChangeBottomLineUpdateOrderEvent.cs | 11 ++ ...ChangeBottomLineUpdateOrderEventHandler.cs | 23 +++ .../EventHandlers/TrackRefreshEventHandler.cs | 102 ++++++++++--- .../Helpers/DateTimeHelper.cs | 21 +++ .../OrderAggregate/IOrderRepository.cs | 8 + .../Aggregates/OrderAggregate/OrderEntity.cs | 6 + .../TrackPullContentConfigEntity.cs | 6 + .../Consts/GlobalConst.MQ.cs | 5 + .../Consts/GlobalConst.Redis.cs | 10 ++ .../Dtos/Common/CityTimezoneDto.cs | 14 ++ .../Dtos/Common/PortTimezoneDto.cs | 14 ++ .../GetTrackPullContentListCacheVO.cs | 10 ++ .../Queries/ITimezoneQueries.cs | 20 +++ .../VEntities/VAirportEntity.cs | 121 +++++++++++++++ .../VEntities/VCityEntity.cs | 140 ++++++++++++++++++ .../Queries/TimezoneQueries.cs | 101 +++++++++++++ .../Repositories/OrderRepository.cs | 5 + 19 files changed, 611 insertions(+), 22 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs create mode 100644 src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs create mode 100644 src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs create mode 100644 src/SJZY.Track.Domain/VEntities/VAirportEntity.cs create mode 100644 src/SJZY.Track.Domain/VEntities/VCityEntity.cs create mode 100644 src/SJZY.Track.Repository/Queries/TimezoneQueries.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs index 1342b38b..24882e20 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs @@ -52,8 +52,14 @@ public class EditTrackPullContentInput /// /// 轨迹时区GMT /// + [Obsolete] public double? TrackTimeZone { get; set; } + /// + /// 兜底轨迹时区发生地 + /// + public int? TrackTimePlaceValue { get; set; } + /// /// 是否完结 /// diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs index 771b328c..a7f2c500 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs @@ -37,13 +37,13 @@ public class TrackPullContentConfigDto /// public int? TrackPlaceValue { get; set; } - /// - /// 轨迹时区GMT值 - /// - public float? TrackTimeZoneValue { get; set; } - /// /// 订单是否完成(由轨迹刷新配置决定) /// public bool IsCompleted { get; set; } + + /// + /// 轨迹时区发生地参数值 + /// + public int? TrackZonePlaceValue { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs new file mode 100644 index 00000000..ed59fce6 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs @@ -0,0 +1,11 @@ +namespace SJZY.Track.Application.Contract.Events; + +public class PullChangeBottomLineUpdateOrderEvent +{ + public List OrderIds { get; set; } = null!; + + /// + /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + public int DeficiencyTagValue { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs new file mode 100644 index 00000000..0365727d --- /dev/null +++ b/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs @@ -0,0 +1,23 @@ +using DotNetCore.CAP; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Consts; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.CAP.EventHandlers; + +public class PullChangeBottomLineUpdateOrderEventHandler :ITransientDependency, ICapSubscribe +{ + private readonly IOrderRepository _orderRepository; + + public PullChangeBottomLineUpdateOrderEventHandler(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + + [CapSubscribe(GlobalConst.PullChangeBottomLineUpdateOrderSubscribe)] + public async Task ConsumerAsync(PullChangeBottomLineUpdateOrderEvent @event) + { + await _orderRepository.UpdateBatchIdsAsync(@event.OrderIds, @event.DeficiencyTagValue); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs index f982343e..26380b66 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs @@ -12,6 +12,7 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Enums; +using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.CAP.EventHandlers; @@ -22,15 +23,17 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe private readonly ICapPublisher _capPublisher; private readonly ITrackPullCacheService _trackPullCacheService; private readonly ITrackDetailsRepository _trackDetailsRepository; + private readonly ITimezoneQueries _timezoneQueries; public TrackRefreshEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher, ITrackPullCacheService trackPullCacheService, - ITrackDetailsRepository trackDetailsRepository) + ITrackDetailsRepository trackDetailsRepository, ITimezoneQueries timezoneQueries) { _orderRepository = orderRepository; _capPublisher = capPublisher; _trackPullCacheService = trackPullCacheService; _trackDetailsRepository = trackDetailsRepository; + _timezoneQueries = timezoneQueries; } [CapSubscribe(GlobalConst.TrackRefreshSubscribe, Group = GlobalConst.TrackRefreshSubscribe)] @@ -172,21 +175,12 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe var trackPlace = paramConfig.TrackPlaceName == null ? null : trackToken[paramConfig.TrackPlaceName]?.Value(); - if (trackPlace.IsNullOrWhiteSpace()) + var hasPlaceBottomLine = false; //执行了兜底但是没有兜底住,需要记录 + if (trackPlace.IsNullOrWhiteSpace() && matchedContentConfig?.TrackPlaceValue != null && matchedContentConfig.TrackPlaceValue.HasValue) { - Expression> resultExpression = - (TrackLocationValue?)matchedContentConfig?.TrackPlaceValue switch - { - TrackLocationValue.ArrivalPort => x => x.ArrivalPort, - TrackLocationValue.ArriveCity => x => x.ArrivalCity, - TrackLocationValue.ArrivalCountry => x => x.ArrivalCountry, - TrackLocationValue.LeavePort => x => x.LeavePort, - TrackLocationValue.LeaveCity => x => x.LeaveCity, - TrackLocationValue.LeaveCountry => x => x.LeaveCountry, - _ => x => x.LeaveCountry - }; - trackPlace = await _orderRepository.GetFirstAsync(x => - x.Id == context.OrderId, resultExpression); + //兜底没配置的就不需要兜底,拉取的发生地没就没 + trackPlace = await GetPlaceByOrder(matchedContentConfig!.TrackPlaceValue.Value,context.OrderId); + hasPlaceBottomLine = string.IsNullOrWhiteSpace(trackPlace); } // 轨迹发生时间 @@ -198,6 +192,17 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe ? null : trackToken[paramConfig.TrackTimeZoneName]?.Value(); + //兜底时区 + var hasTimezoneBottomLine = false; //执行了兜底但是没有兜底住,需要记录 + if (!trackTimeZone.HasValue && matchedContentConfig?.TrackZonePlaceValue != null && matchedContentConfig.TrackZonePlaceValue.HasValue) + { + //兜底没配置的就不需要兜底,拉取的发生地没就没 + var timezone= await GetTimezone(matchedContentConfig,context.OrderId); + + trackTimeZone = timezone; + hasTimezoneBottomLine = !timezone.HasValue; + } + if (matchedContentConfig is null) { var notMappedEvent = new TrackInsertForNotMappedEvent @@ -209,7 +214,7 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe OriginTrackData = JsonConvert.SerializeObject(trackToken), TrackPlace = trackPlace ?? GlobalConst.EmptyString, TrackTime = trackTime ?? DateTime.Now, - TrackTimeZone = trackTimeZone ?? matchedContentConfig?.TrackTimeZoneValue ?? 8 + TrackTimeZone = trackTimeZone ?? 8 }; if (paramConfig.TrackContentName != null) { @@ -246,11 +251,74 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe TrackCode = matchedContentConfig.TrackContentCode, TrackPlace = trackPlace ?? GlobalConst.EmptyString, TrackTime = trackTime ?? DateTime.Now, - TrackTimeZone = trackTimeZone ?? matchedContentConfig.TrackTimeZoneValue ?? 8 + TrackTimeZone = trackTimeZone ?? 8 }; trackUpsertEvent.IsAdd = !await _trackDetailsRepository.AnyByCodeAsync(context.OrderId, matchedContentConfig.TrackContentCode); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent); + + // 触发了兜底,但是没有兜底住,对订单进行标记 + if (hasPlaceBottomLine || hasTimezoneBottomLine) + { + //1表示时区,2表示发生地,3表示两种 + var placeTagValue = hasPlaceBottomLine ? 2 : 0; + var timezoneTagValue = hasTimezoneBottomLine ? 1 : 0; + PullChangeBottomLineUpdateOrderEvent deficiencyTagEvent = new PullChangeBottomLineUpdateOrderEvent + { + OrderIds = new List(){context.OrderId}, + DeficiencyTagValue = placeTagValue+timezoneTagValue + }; + await _capPublisher.PublishAsync(GlobalConst.PullChangeBottomLineUpdateOrderSubscribe, deficiencyTagEvent); + } + } + + /// + /// 根据订单id获取兜底位置 + /// + /// + /// + /// + private Task GetPlaceByOrder(int trackValue,int orderId) + { + Expression> resultExpression = + (TrackLocationValue)trackValue switch + { + TrackLocationValue.ArrivalPort => x => x.ArrivalPort, + TrackLocationValue.ArriveCity => x => x.ArrivalCity, + TrackLocationValue.ArrivalCountry => x => x.ArrivalCountry, + TrackLocationValue.LeavePort => x => x.LeavePort, + TrackLocationValue.LeaveCity => x => x.LeaveCity, + TrackLocationValue.LeaveCountry => x => x.LeaveCountry, + _ => x => x.LeaveCountry + }; + return _orderRepository.GetFirstAsync(x => x.Id == orderId, resultExpression); + } + + /// + /// 获取时区 + /// + /// + /// + /// + private async Task GetTimezone(TrackPullContentConfigDto matchedContentConfig,int orderId ) + { + var placeOrCode = await GetPlaceByOrder(matchedContentConfig!.TrackZonePlaceValue.Value,orderId); + string timezone = null; + if (!string.IsNullOrEmpty(placeOrCode)) + { + + if (matchedContentConfig!.TrackZonePlaceValue.Value == (int)TrackLocationValue.ArrivalPort + || matchedContentConfig!.TrackZonePlaceValue.Value == (int)TrackLocationValue.LeavePort) + { + timezone = await _timezoneQueries.GetPortTimezone(placeOrCode); + return DateTimeHelper.ConvertTimeZoneToFloat(timezone); + } + + timezone = await _timezoneQueries.GetCityTimezone(placeOrCode); + return DateTimeHelper.ConvertTimeZoneToFloat(timezone); + } + + return null; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs index 907cab70..afc41d27 100644 --- a/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs +++ b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs @@ -36,4 +36,25 @@ public static class DateTimeHelper //时区是整数丢掉浮点数部分 return format.Replace("hh", ((int)timezone).ToString()); } + + /// + /// 转换主数据中心类似GMT-09:00这种的时区为浮点数 + /// + /// 分区 + /// + /// + public static float? ConvertTimeZoneToFloat(string timeZone) + { + if (string.IsNullOrEmpty(timeZone)|| !timeZone.StartsWith("GMT")) + { + return null; + } + + var sign = timeZone[3] == '+' ? 1 : -1; + var parts = timeZone.Substring(4).Split(':'); + var hours = int.Parse(parts[0]); + var minutes = int.Parse(parts[1]); + + return sign * (hours + minutes / 60f); + } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs index 78cdd5df..ff7ab6f7 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs @@ -31,6 +31,14 @@ public interface IOrderRepository : IBasicRepository /// Task PushWarnOrdersAsync(); + /// + /// 更新缺失标记,时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + /// 订单id + /// 值 + /// + Task UpdateBatchIdsAsync(List ids, int newValue); + #region 订单关联 /// diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index 9a7c4597..b04aa76a 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -149,6 +149,12 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "ProductCode")] public string? ProductCode { get; set; } + + /// + /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + [SugarColumn(ColumnName = "DeficiencyTag")] + public int? DeficiencyTag { get; set; } [SugarColumn(IsIgnore = true)] public List OrderFlights { get; set; } [SugarColumn(IsIgnore = true)] public List OrderTemplates { get; set; } diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs index 5afef0fb..6e717032 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs @@ -71,4 +71,10 @@ public class TrackPullContentConfigEntity : IFullAuditedBasicEntitys, IEntity /// [SugarColumn(ColumnName = "IsCompleted")] public bool IsCompleted { get; set; } + + /// + /// 轨迹时区发生地参数值 + /// + [SugarColumn(ColumnName = "TrackZonePlaceValue")] + public int? TrackZonePlaceValue { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs index 378f0b89..1b853ffe 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs @@ -56,4 +56,9 @@ public partial class GlobalConst /// 关联订单后补轨迹 /// public const string OrderLinkAfterFillTrack = "SJZY.Track.OrderLinkAfterFillTrack"; + + /// + /// 拉取轨迹触发兜底后更新订单 + /// + public const string PullChangeBottomLineUpdateOrderSubscribe = "SJZY.Track.PullChangeBottomLineUpdateOrder"; } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index dcaf7a35..6f49c80d 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -36,4 +36,14 @@ public partial class GlobalConst /// kpi区域redis key前缀 /// public const string KpiAreaKeyPrefix = "KpiArea"; + + /// + /// 城市时区redis key前缀 + /// + public const string CityTimezoneKeyPrefix = "CityTimezone"; + + /// + /// 港口时区redis key前缀 + /// + public const string PortTimezoneKeyPrefix = "PortTimezone"; } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs b/src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs new file mode 100644 index 00000000..63cd5dad --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Common; + +public class CityTimezoneDto +{ + /// + /// 城市英文名称 + /// + public string? CityEnName { get; set; } + + /// + /// 时区 + /// + public string Timezone { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs b/src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs new file mode 100644 index 00000000..896981cb --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Common; + +public class PortTimezoneDto +{ + /// + /// 城市英文名称 + /// + public string? PortCode { get; set; } + + /// + /// 时区 + /// + public string Timezone { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs index 047431d9..8fad0074 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs @@ -36,6 +36,11 @@ public class GetTrackPullContentListCacheVO /// 轨迹发生地参数值(主数据枚举) /// public int? TrackPlaceValue { get; set; } + + /// + /// 兜底时区轨迹发生地参数值(TrackLocationValue) + /// + public int? TrackTimePlaceValue { get; set; } /// /// 轨迹时区GMT @@ -46,4 +51,9 @@ public class GetTrackPullContentListCacheVO /// 订单是否完成(由轨迹刷新配置决定) /// public bool IsCompleted { get; set; } + + /// + /// 轨迹时区发生地参数值 + /// + public int? TrackZonePlaceValue { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs b/src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs new file mode 100644 index 00000000..14e33748 --- /dev/null +++ b/src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs @@ -0,0 +1,20 @@ +using SJZY.Track.Domain.Dtos.Common; + +namespace SJZY.Track.Domain.Queries; + +public interface ITimezoneQueries +{ + /// + /// 通过城市英文名称获取时区 + /// + /// + /// + Task GetCityTimezone(string cityEnName); + + /// + /// 通过港口三字码获取时区 + /// + /// + /// + Task GetPortTimezone(string airCode); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/VEntities/VAirportEntity.cs b/src/SJZY.Track.Domain/VEntities/VAirportEntity.cs new file mode 100644 index 00000000..ba69e854 --- /dev/null +++ b/src/SJZY.Track.Domain/VEntities/VAirportEntity.cs @@ -0,0 +1,121 @@ +using SqlSugar; + +namespace SJZY.Track.Domain.VEntities; + +/// +/// 空港 +/// +[SugarTable("t_airport", "空港")] +public class VAirportEntity : IFullAuditedBasicEntitys +{ + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 空运航线id + /// + [SugarColumn(ColumnName = "AirRouteId")] + public int AirRouteId { get; set; } + + /// + /// 城市id + /// + [SugarColumn(ColumnName = "CityId")] + public int CityId { get; set; } + + /// + /// 主港口,空港id + /// + [SugarColumn(ColumnName = "MId", IsNullable = true)] + public int? MId { get; set; } + + /// + /// 中文名 + /// + [SugarColumn(ColumnName = "CnName")] + public string CnName { get; set; } + + /// + /// 英文名 + /// + [SugarColumn(ColumnName = "EnName")] + public string EnName { get; set; } + + /// + /// 代码 + /// + [SugarColumn(ColumnName = "Code", IsNullable = true)] + public string Code { get; set; } + + /// + /// 海关代码 + /// + [SugarColumn(ColumnName = "CustomsCode", IsNullable = true)] + public string CustomsCode { get; set; } + + /// + /// 海关名称 + /// + [SugarColumn(ColumnName = "CustomsName", IsNullable = true)] + public string CustomsName { get; set; } + + /// + /// 离境口岸代码 + /// + [SugarColumn(ColumnName = "DeparturePortCode", IsNullable = true)] + public string DeparturePortCode { get; set; } + + /// + /// 离境口岸名称 + /// + [SugarColumn(ColumnName = "DeparturePortName", IsNullable = true)] + public string DeparturePortName { get; set; } + + /// + /// 国内排序 + /// + [SugarColumn(ColumnName = "DomcSort")] + public int DomcSort { get; set; } + + /// + /// 国外排序 + /// + [SugarColumn(ColumnName = "OverSort")] + public int OverSort { get; set; } + + /// + /// 备注 + /// + [SugarColumn(ColumnName = "Remark", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", IsNullable = true)] + public int? CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", IsNullable = false, DefaultValue = "CURRENT_TIMESTAMP")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", IsNullable = true)] + public int? UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", IsNullable = true)] + public DateTime? UpdateTime { get; set; } + + /// + /// 是否删除 + /// + [SugarColumn(ColumnName = "IsDeleted")] + public bool IsDeleted { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/VEntities/VCityEntity.cs b/src/SJZY.Track.Domain/VEntities/VCityEntity.cs new file mode 100644 index 00000000..ad914504 --- /dev/null +++ b/src/SJZY.Track.Domain/VEntities/VCityEntity.cs @@ -0,0 +1,140 @@ +using SqlSugar; +using System; + +namespace SJZY.Track.Domain.VEntities; + +[SugarTable("t_city")] +public class VCityEntity : IFullAuditedBasicEntitys +{ + /// + /// 主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 国家id + /// + [SugarColumn(ColumnName = "CountryId")] + public int CountryId { get; set; } + + /// + /// 省份id + /// + [SugarColumn(ColumnName = "ProvinceId", IsNullable = true)] + public int? ProvinceId { get; set; } + + /// + /// 中文名 + /// + [SugarColumn(ColumnName = "CnName")] + public string CnName { get; set; } + + /// + /// 英文名 + /// + [SugarColumn(ColumnName = "EnName")] + public string EnName { get; set; } + + /// + /// 联合国code + /// + [SugarColumn(ColumnName = "UnCode", IsNullable = true)] + public string UnCode { get; set; } + + /// + /// 所区分组(1华南,2华东,3华北,4 西南,5华中) + /// + [SugarColumn(ColumnName = "CityType", IsNullable = true)] + public int? CityType { get; set; } + + /// + /// 时区 + /// + [SugarColumn(ColumnName = "TimeZone", IsNullable = true)] + public string TimeZone { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnName = "Sort")] + public int Sort { get; set; } + + /// + /// 备注 + /// + [SugarColumn(ColumnName = "Remark", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 国家统计局统计用区划代码 + /// + [SugarColumn(ColumnName = "StatisticalZoningCode", IsNullable = true)] + public string StatisticalZoningCode { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", IsNullable = true)] + public int? CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", IsNullable = false, DefaultValue = "CURRENT_TIMESTAMP")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", IsNullable = true)] + public int? UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", IsNullable = true)] + public DateTime? UpdateTime { get; set; } + + /// + /// 是否删 + /// + [SugarColumn(ColumnName = "IsDeleted")] + public bool IsDeleted { get; set; } + + /// + /// 维护时区 + /// + [SugarColumn(ColumnName = "MaintainTimeZone", IsNullable = true)] + public decimal? MaintainTimeZone { get; set; } + + /// + /// 经度 + /// + [SugarColumn(ColumnName = "Longitude", IsNullable = true)] + public string Longitude { get; set; } + + /// + /// 纬度 + /// + [SugarColumn(ColumnName = "Latitude", IsNullable = true)] + public string Latitude { get; set; } + + /// + /// 海拔 + /// + [SugarColumn(ColumnName = "Elevation", IsNullable = true)] + public string Elevation { get; set; } + + /// + /// 语言 + /// + [SugarColumn(ColumnName = "Language", IsNullable = true)] + public string Language { get; set; } + + /// + /// timezoneURL + /// + [SugarColumn(ColumnName = "TimezoneURL", IsNullable = true)] + public string TimezoneURL { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Queries/TimezoneQueries.cs b/src/SJZY.Track.Repository/Queries/TimezoneQueries.cs new file mode 100644 index 00000000..cd2a0569 --- /dev/null +++ b/src/SJZY.Track.Repository/Queries/TimezoneQueries.cs @@ -0,0 +1,101 @@ +using System.Reflection.Metadata; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Queries; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Queries; + +public class TimezoneQueries:ITimezoneQueries, ISugarRepository, ITransientDependency +{ + public ISqlSugarClient Context { get; set; } + + public TimezoneQueries() + { + Context = SqlsugarScopeBasic.GetContextSafely("default"); + } + + private string GetCityKey(string cityEnName) + { + return $"{GlobalConst.CityTimezoneKeyPrefix}:{cityEnName}"; + } + + private string GetPortKey(string airCode) + { + return $"{GlobalConst.PortTimezoneKeyPrefix}:{airCode}"; + } + + /// + /// 获取城市时区 + /// + /// 城市英文名称 + /// 时区 + public async Task GetCityTimezone(string cityEnName) + { + var key =GetCityKey(cityEnName); + var timezone = RedisHelper.Client.Get(key); + if (!string.IsNullOrEmpty(timezone)) + { + return timezone; + } + + var cityTimezone = await GetTimezoneByCityName(cityEnName); + if (cityTimezone == null!) + { + await RedisHelper.Client.SetAsync(key, string.Empty, TimeSpan.FromSeconds(20)); + return string.Empty; + } + + await RedisHelper.Client.SetAsync(key, cityTimezone.Timezone, TimeSpan.FromHours(6)); + return cityTimezone.Timezone; + } + + /// + /// 获取港口时区 + /// + /// 港口三字码 + /// 时区 + public async Task GetPortTimezone(string airCode) + { + var key = GetPortKey(airCode); + var timezone = RedisHelper.Client.Get(key); + if (!string.IsNullOrEmpty(timezone)) + { + return timezone; + } + + var portTimezone = await GetTimezoneByPortCode(airCode); + if (portTimezone == null!) + { + await RedisHelper.Client.SetAsync(key, string.Empty, TimeSpan.FromSeconds(20)); + return string.Empty; + } + + await RedisHelper.Client.SetAsync(key, portTimezone.Timezone, TimeSpan.FromHours(6)); + return portTimezone.Timezone; + } + + private Task GetTimezoneByCityName(string cityEnName) + { + return Context.Queryable().Where(val => !val.IsDeleted && val.EnName == cityEnName) + .Select(val=>new CityTimezoneDto() + { + CityEnName =val.EnName, + Timezone = val.TimeZone + }) + .FirstAsync(); + } + + private Task GetTimezoneByPortCode(string airCode) + { + return Context.Queryable() + .InnerJoin((city, airport) => city.Id == airport.CityId) + .Where((city,airport) => !airport.IsDeleted && !city.IsDeleted && airport.Code == airCode) + .Select((city,airport)=>new PortTimezoneDto() + { + PortCode = airport.Code, + Timezone = city.TimeZone + }) + .FirstAsync(); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index 85faff5d..85df94ed 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -19,6 +19,11 @@ public class OrderRepository : BasicRepository, IOrderRepository, I tran.Complete(); } + public Task UpdateBatchIdsAsync(List ids, int newValue) + { + return Context.Ado.ExecuteCommandAsync("UPDATE `t_order` SET `DeficiencyTag` = @newValue WHERE `Id` IN @ids", new { ids, newValue }); + } + public async Task UpdateOrderAsync(OrderEntity order) { using var tran = TransactionHelper.GetReadCommitted(); From 061cffc6c3bfbcccd57b16d60f46d5bbf4d6c121 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 12:59:01 +0800 Subject: [PATCH 26/60] =?UTF-8?q?add=EF=BC=9A=E9=A2=84=E8=AD=A6crud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Forewarning/CreateWarningInput.cs | 42 +++++ .../Dtos/Forewarning/EditWarningOutput.cs | 58 ++++++ .../Dtos/Forewarning/UpdateWarningInput.cs | 45 +++++ .../Helpers/ForewarningHelper.cs | 168 ++++++++++++------ .../ForewarningServices/ForewarningService.cs | 142 +++++++++++---- .../Forewarning/CreateRuleFactorValidation.cs | 1 + .../Forewarning/RuleTrackStateDtoValidator.cs | 2 +- .../IWarningRepository.cs | 32 +++- .../ForewarningAggregate/WarningEntity.cs | 30 +++- .../WarningFactorEntity.cs | 2 +- .../WarningNotifyEntity.cs | 48 +++++ .../ForewarningAggregate/WarningRuleEntity.cs | 2 +- .../Dtos/Forewarning/CreateRuleRequest.cs | 48 ----- ...ckStatusSpanDto.cs => WarningNitifyDto.cs} | 2 +- ...{WarningRuleOutput.cs => WarningRuleVo.cs} | 4 +- .../VEntities/VExternalSubjectEntity.cs | 2 +- src/SJZY.Track.Repository/DataBaseContext.cs | 37 ++-- .../Queries/TrackOrderQueries.cs | 1 - .../Repositories/TrackPushConfigRepository.cs | 1 - .../Repositories/WarningRepository.cs | 65 +++++-- 20 files changed, 530 insertions(+), 202 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs rename src/SJZY.Track.Domain/Dtos/Forewarning/{TrackStatusSpanDto.cs => WarningNitifyDto.cs} (92%) rename src/SJZY.Track.Domain/Dtos/Forewarning/{WarningRuleOutput.cs => WarningRuleVo.cs} (94%) diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs new file mode 100644 index 00000000..0179e744 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs @@ -0,0 +1,42 @@ +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class CreateWarningInput +{ + /// + /// 模板名称 + /// + public string Name { get; set; } = null!; + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } + + /// + /// 通知方式 + /// + public NotifyMode NotifyMode { get; set; } + + /// + /// 通知模板 + /// + public string NotifyTemplate { get; set; } = null!; + + /// + /// 轨迹状态跨度列表 + /// + public List TrackStatusSpans { get; set; } = new(); + + /// + /// 预警因素列表。 + /// + public List WarningFactors { get; set; } = new(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs new file mode 100644 index 00000000..f8c65d67 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs @@ -0,0 +1,58 @@ +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class EditWarningOutput +{ + /// + /// 模板名称 + /// + public string Name { get; set; } = null!; + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } + + /// + /// 通知方式 + /// + public NotifyMode NotifyMode { get; set; } + + /// + /// 通知模板 + /// + public string NotifyTemplate { get; set; } = null!; + + /// + /// 通知列表 + /// + public List TrackStatusSpans { get; set; } = new(); + + /// + /// 预警因素列表。 + /// + public List WarningFactors { get; set; } = new(); +} + +public class WarningNotifyWithIdDto: WarningNitifyDto +{ + /// + /// 通知id + /// + public int Id { get; set; } +} + +public class WarningFactorWithIdDto : WarningFactorDto +{ + /// + /// 因素id + /// + public int Id { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs new file mode 100644 index 00000000..0d00a8d3 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs @@ -0,0 +1,45 @@ +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class UpdateWarningInput +{ + /// + /// 预警id + /// + public int Id { get; set; } + + /// + /// 模板名称 + /// + public string Name { get; set; } = null!; + + /// + /// 通知方式 + /// + public NotifyMode NotifyMode { get; set; } + + /// + /// 通知模板 + /// + public string NotifyTemplate { get; set; } = null!; + + /// + /// 通知列表 + /// + public List Notifies { get; set; } = new(); +} + +public class NotifyDto +{ + /// + /// 通知id + /// + public int Id { get; set; } + + /// + /// 通知人id + /// + public int NotifyUserId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index c945e018..c03be716 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -1,8 +1,10 @@ using Newtonsoft.Json.Linq; using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.Enums; +using SqlSugar; namespace SJZY.Track.Application.Helpers; @@ -14,9 +16,14 @@ public class ForewarningHelper /// /// /// - public static List CalcRuleList(List statusSpans, + public static List CalcRuleList(List statusSpans, List factors) { + if (statusSpans.Count == 0 || factors.Count == 0) + { + throw new BusinessException(message: "轨迹状态区间或因素列表为空"); + } + var len = statusSpans.Count * factors.Select(f => f.FactorValue.Count).Aggregate((pre, cur) => pre * cur); if (len == 0) { @@ -32,19 +39,18 @@ public class ForewarningHelper foreach (var factor in factors) { var factorValueCount = factor.FactorValue.Count; - repeat /= factor.FactorValue.Count; // repeat梯度下降,与times成反比关系 - - for (int time = 0; time < len / repeat / factorValueCount; time++) - { - FillFactor(factor, rules, repeat, time); - } + + // repeat梯度下降,与times成反比关系 + repeat /= factor.FactorValue.Count; + var times = len / repeat / factorValueCount; + FillFactor(factor, rules, repeat, times); } return rules; } - private static void FillStatus(List statusSpans, List rules, int repeat) + private static void FillStatus(List statusSpans, List rules, int repeat) { for (var i = 0; i < statusSpans.Count; i++) { @@ -59,70 +65,77 @@ public class ForewarningHelper } } - private static void FillFactor(WarningFactorDto factor, List rules, int repeat, int time) + private static void FillFactor(WarningFactorDto factor, List rules, int repeat, int times) { - for (var i = 0; i < factor.FactorValue.Count * time; i++) + var row = 0; + for (var i = 0; i < times; i++) { - for (var j = 0; j < repeat; j++) + foreach (var value in factor.FactorValue) { - var row = i * repeat + j; - var value = factor.FactorValue[row]; var strValue = value.ToString(); - switch (factor.FactorType) + if (strValue.IsNullOrEmpty()) { - case RuleFactorType.CargoType: - if (value.Type is not JTokenType.String) - { - throw new BusinessException(message: "货物类型只接收字符串"); - } + throw new BusinessException(message: "因素值不能为空"); + } - rules[row].CargoType = strValue; - break; - case RuleFactorType.Months: - foreach (var item in strValue.Split("/")) - { - if (!int.TryParse(item, out var month) || month < 1 || month > 12) + for (var j = 0; j < repeat; j++, row++) + { + switch (factor.FactorType) + { + case RuleFactorType.CargoType: + if (value.Type is not JTokenType.String) { - throw new BusinessException(message: "请输入合法的月份,多个月份请以'/'连接"); + throw new BusinessException(message: "货物类型只接收字符串"); } - } - rules[row].Months = strValue; - break; - case RuleFactorType.Areas: - if (value.Type is not JTokenType.Integer) - { - throw new BusinessException(message: "分区请传id"); - } + rules[row].CargoType = strValue; + break; + case RuleFactorType.Months: + foreach (var item in strValue.Split("/")) + { + if (!int.TryParse(item, out var month) || month < 1 || month > 12) + { + throw new BusinessException(message: "请输入合法的月份,多个月份请以'/'连接"); + } + } - rules[row].AreaId = int.Parse(strValue); - break; - case RuleFactorType.IsTransit: - if (value.Type is not JTokenType.Boolean) - { - throw new BusinessException(message: "是否中转只接收bool类型"); - } + rules[row].Months = strValue; + break; + case RuleFactorType.Areas: + if (value.Type is not JTokenType.Integer) + { + throw new BusinessException(message: "分区请传id"); + } - rules[row].IsTransit = bool.Parse(strValue); - break; - case RuleFactorType.LeavePort: - if (value.Type is not JTokenType.String) - { - throw new BusinessException(message: "货物类型只接收字符串"); - } + rules[row].AreaId = int.Parse(strValue); + break; + case RuleFactorType.IsTransit: + if (value.Type is not JTokenType.Boolean) + { + throw new BusinessException(message: "是否中转只接收bool类型"); + } - rules[row].LeavePort = strValue; - break; - case RuleFactorType.ProductCode: - if (value.Type is not JTokenType.String) - { - throw new BusinessException(message: "货物类型只接收字符串"); - } + rules[row].IsTransit = bool.Parse(strValue); + break; + case RuleFactorType.LeavePort: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "货物类型只接收字符串"); + } - rules[row].ProductCode = strValue; - break; - default: - throw new BusinessException(message: $"不支持的因素:{factor.FactorType}"); + rules[row].LeavePort = strValue; + break; + case RuleFactorType.ProductCode: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "货物类型只接收字符串"); + } + + rules[row].ProductCode = strValue; + break; + default: + throw new BusinessException(message: $"不支持的因素:{factor.FactorType}"); + } } } } @@ -136,4 +149,41 @@ public class ForewarningHelper Value = x.FactorValue.ToJson() }).ToList(); } + + public static List MapNotifyEntities(CreateWarningInput input) + { + return input.TrackStatusSpans.Select(x => new WarningNotifyEntity + { + StartTrackStatusId = x.StartTrackStatusId, + EndTrackStatusId = x.EndTrackStatusId, + NotifyMode = input.NotifyMode, + NotifyTemplate = input.NotifyTemplate, + NotifyUserId = x.NotifyUserId + }).ToList(); + } + + public static EditWarningOutput MapWarningSummary(WarningEntity warning) + { + return new EditWarningOutput + { + Name = warning.Name, + SubSystemId = warning.SubSystemId, + CustomerId = warning.CustomerId, + NotifyMode = warning.WarningNotifies.First().NotifyMode, + NotifyTemplate = warning.WarningNotifies.First().NotifyTemplate, + TrackStatusSpans = warning.WarningNotifies.Select(x => new WarningNotifyWithIdDto + { + Id = x.Id, + StartTrackStatusId = x.StartTrackStatusId, + EndTrackStatusId = x.EndTrackStatusId, + NotifyUserId = x.NotifyUserId, + }).ToList(), + WarningFactors = warning.WarningFactors.Select(x => new WarningFactorWithIdDto + { + Id = x.Id, + FactorType = x.Type, + FactorValue = JArray.Parse(x.Value), + }).ToList() + }; + } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index 6a1b011d..6d8a61d4 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -16,7 +16,19 @@ public class ForewarningService : ApplicationService { _warningRepository = warningRepository; } - + + /// + /// 获取预警分页列表 + /// + /// + /// + [HttpPost("GetWarningPageList")] + public async Task> GetWarningPageList(GetWarningPageInputVo inputVo) + { + if (!inputVo.KeyWord.IsNullOrEmpty()) inputVo.KeyWord = inputVo.KeyWord!.Trim(); + return await _warningRepository.GetWarningPageListAsync(inputVo); + } + /// /// 创建预警 /// @@ -28,10 +40,106 @@ public class ForewarningService : ApplicationService var warning = ObjectMapper.Map(input); warning.WarningRules = ForewarningHelper.CalcRuleList(input.TrackStatusSpans, input.WarningFactors); warning.WarningFactors = ForewarningHelper.MapFactorEntities(input.WarningFactors); + warning.WarningNotifies = ForewarningHelper.MapNotifyEntities(input); await _warningRepository.CreateForewarningAsync(warning); return true; } + + /// + /// 编辑预警 + /// + /// + /// + [HttpPost("EditWarning")] + public async Task EditWarning(int warningId) + { + var warning = await _warningRepository.GetByIdAsync(warningId); + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + return ForewarningHelper.MapWarningSummary(warning); + } + + /// + /// 更新预警 + /// + /// + /// + [HttpPost("UpdateWarning")] + public async Task UpdateWarning(UpdateWarningInput input) + { + var warning = await _warningRepository.GetFirstAsync(x => x.Id == input.Id); + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + if (await _warningRepository.IsAnyAsync(x => + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.Id != warning.Id)) + { + throw new BusinessException(message: "该子系统下的客户已经存在一个同名预警: " + warning.Name); + } + + warning.SetName(input.Name); + + warning.WarningNotifies = input.Notifies.Select(x => new WarningNotifyEntity + { + Id = x.Id, + NotifyMode = input.NotifyMode, + NotifyTemplate = input.NotifyTemplate, + NotifyUserId = x.NotifyUserId + }).ToList(); + + await _warningRepository.UpdateForewarningAsync(warning); + + return true; + } + + /// + /// 启用or禁用预警 + /// + /// 预警id + /// 是否启用 + /// + [HttpPost("TurnWarning")] + public async Task TurnWarning(int warningId, bool isEnable) + { + var warning = await _warningRepository.GetFirstAsync(x => x.Id == warningId); + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + if (isEnable) + { + if (await _warningRepository.IsAnyAsync(x => + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.IsEnable)) + { + throw new BusinessException(message: "该子系统下的客户已经存在一个启用的预警,请先禁用"); + } + } + + warning.SetEnable(isEnable); + + return await _warningRepository.TurnWarningAsync(warning); + } + + /// + /// 查询预警规则列表 + /// + /// 预警规则id + /// + [HttpGet("GetWarningRuleList")] + public async Task> GetWarningRuleListAsync([Required] int warningId) + { + var rules = await _warningRepository.GetWarningRuleListAsync(warningId); + + return rules; + } + /// /// 修改预警规则时效 /// @@ -54,36 +162,4 @@ public class ForewarningService : ApplicationService return true; } - - - /// - /// 获取预警分页列表 - /// - /// - /// - [HttpPost("GetWarningPageList")] - public async Task> GetWarningPageList(GetWarningPageInputVo inputVo) - { - if (!inputVo.KeyWord.IsNullOrEmpty()) inputVo.KeyWord = inputVo.KeyWord!.Trim(); - return await _warningRepository.GetWarningPageListAsync(inputVo); - } - - /// - /// 查询预警规则列表 - /// - /// 预警规则id - /// - [HttpGet("GetWarningRuleList")] - public async Task> GetWarningRuleListAsync([Required] int warningId) - { - return await _warningRepository.GetWarningRuleListAsync(warningId); - } - - /// - /// 发送预警通知 - /// - [HttpPost("SendForewarningNotification")] - public void SendForewarningNotification() - { - } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs index cc5cd662..40f58dd3 100644 --- a/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs +++ b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs @@ -1,4 +1,5 @@ using FluentValidation; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Application.Validations.Forewarning; diff --git a/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs index 7dab2f60..cf61bc45 100644 --- a/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs +++ b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs @@ -3,7 +3,7 @@ using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Application.Validations.Forewarning; -public class RuleTrackStateDtoValidator : AbstractValidator +public class RuleTrackStateDtoValidator : AbstractValidator { public RuleTrackStateDtoValidator() { diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs index b3f6bd97..efa73bbd 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs @@ -5,18 +5,11 @@ namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; public interface IWarningRepository : IBasicRepository { /// - /// 创建预警 + /// 创建预警,include factors, notifies, rules /// /// /// Task CreateForewarningAsync(WarningEntity warning); - - /// - /// 修改预警 - /// - /// - /// - Task UpdateForewarningAsync(WarningEntity warning); /// /// 复制预警 @@ -37,7 +30,14 @@ public interface IWarningRepository : IBasicRepository /// /// 预警id /// - Task> GetWarningRuleListAsync(int warningId); + Task> GetWarningRuleListAsync(int warningId); + + /// + /// 修改预警 + /// + /// + /// + Task UpdateForewarningAsync(WarningEntity warning); /// /// 修改预警时效 @@ -45,4 +45,18 @@ public interface IWarningRepository : IBasicRepository /// /// Task ModifyTimeSpansAsync(List inputItems); + + /// + /// 启用预警 + /// + /// + /// + Task TurnWarningAsync(WarningEntity warning); + + /// + /// 获取预警,include factors, notifies + /// + /// + /// + Task GetByIdAsync(int warningId); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs index b713ffe0..abfc0064 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs @@ -1,3 +1,6 @@ +using SJZY.Track.Domain.Enums; +using Volo.Abp; + namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; [SugarTable("t_warning")] @@ -21,12 +24,6 @@ public class WarningEntity: IFullAuditedBasicEntitys, IAggregateRoot [SugarColumn(ColumnName = "CustomerId")] public int CustomerId { get; set; } - /// - /// 客户 - /// - [SugarColumn(ColumnName = "CustomerName", Length = 255)] - public string CustomerName { get; set; } = null!; - /// /// 规则模板名称,KPI名称 /// @@ -50,4 +47,25 @@ public class WarningEntity: IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(IsIgnore = true)] public List WarningFactors { get; set; } = new(); + + /// + /// 预警通知 + /// + [SugarColumn(IsIgnore = true)] + public List WarningNotifies { get; set; } = new(); + + public void SetName(string name) + { + Name = name; + } + + public void SetEnable(bool isEnable) + { + if (IsEnable == isEnable) + { + throw new BusinessException(message: $"预警已经是{(isEnable ? "启用" : "禁用")}状态"); + } + + IsEnable = isEnable; + } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs index 62a37538..46d9c4d8 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs @@ -2,7 +2,7 @@ using SJZY.Track.Domain.Enums; namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; -public class WarningFactorEntity : IFullAuditedBasicEntitys +public class WarningFactorEntity : IFullAuditedBasicEntitys, IEntity { /// /// 自增主键 diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs new file mode 100644 index 00000000..1b08f86f --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs @@ -0,0 +1,48 @@ +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public class WarningNotifyEntity : IFullAuditedBasicEntitys, IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 预警id + /// + [SugarColumn(ColumnName = "WarningId")] + public int WarningId { get; set; } + + /// + /// 起始轨迹状态id + /// + [SugarColumn(ColumnName = "StartTrackStatusId", IsNullable = false)] + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + [SugarColumn(ColumnName = "EndTrackStatusId", IsNullable = false)] + public int EndTrackStatusId { get; set; } + + /// + /// 通知方式 + /// + [SugarColumn(ColumnName = "NotifyMode")] + public NotifyMode NotifyMode { get; set; } + + /// + /// 通知模板 + /// + [SugarColumn(ColumnName = "NotifyTemplate", Length = 256)] + public string NotifyTemplate { get; set; } = null!; + + /// + /// 通知人 + /// + [SugarColumn(ColumnName = "NotifyUserId")] + public int NotifyUserId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs index ce26f2a1..4baac33e 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs @@ -1,7 +1,7 @@ namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; [SugarTable("t_warning_rule")] -public class WarningRuleEntity : IFullAuditedBasicEntitys +public class WarningRuleEntity : IFullAuditedBasicEntitys, IEntity { /// /// 自增主键 diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs deleted file mode 100644 index 0226853e..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleRequest.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using SJZY.Track.Domain.Enums; - -namespace SJZY.Track.Domain.Dtos.Forewarning -{ - public class CreateWarningInput - { - /// - /// 模板名称 - /// - public string Name { get; set; } = null!; - - /// - /// 子系统id - /// - public int SubSystemId { get; set; } - - /// - /// 客户id - /// - public int CustomerId { get; set; } - - /// - /// 客户名称 - /// - public string CustomerName { get; set; } = null!; - - /// - /// 通知方式 - /// - public NotifyMode NotifyMode { get; set; } - - /// - /// 通知模板 - /// - public string NotifyTemplate { get; set; } = null!; - - /// - /// 轨迹状态跨度列表 - /// - public List TrackStatusSpans { get; set; } = new(); - - /// - /// 预警因素列表。 - /// - public List WarningFactors { get; set; } = new(); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs similarity index 92% rename from src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs rename to src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs index f9eda466..255a421a 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/TrackStatusSpanDto.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; -public class TrackStatusSpanDto +public class WarningNitifyDto { /// /// 起始轨迹状态id diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleVo.cs similarity index 94% rename from src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs rename to src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleVo.cs index c614eb38..439393e1 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleOutput.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleVo.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; -public class WarningRuleOutput +public class WarningRuleVo { /// /// 自增主键 @@ -45,7 +45,7 @@ public class WarningRuleOutput /// /// 区域 /// - public int? AreaId { get; set; } + public string? Area { get; set; } /// /// 是否中转 diff --git a/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs b/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs index 51bea216..1743a9fd 100644 --- a/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs +++ b/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Repository.VData.Entitys; +namespace SJZY.Track.Domain.VEntities; /// /// 外部主体 diff --git a/src/SJZY.Track.Repository/DataBaseContext.cs b/src/SJZY.Track.Repository/DataBaseContext.cs index 88539836..afc9be0c 100644 --- a/src/SJZY.Track.Repository/DataBaseContext.cs +++ b/src/SJZY.Track.Repository/DataBaseContext.cs @@ -20,21 +20,20 @@ public class DataBaseContext //新增 if (entityInfo.OperationType == DataFilterType.InsertByObject) { + var time = DateTime.Now; + var userId = CurrentUserRequest.CurrentUser.UserId; + if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateTime)) - entityInfo.SetValue(DateTime.Now); - if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateUserId)) + entityInfo.SetValue(time); + else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateTime)) + entityInfo.SetValue(time); + else if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateUserId)) { - if (oldValue == null || (int)oldValue == 0) - { - try - { - entityInfo.SetValue(CurrentUserRequest.CurrentUser?.UserId); - } - catch - { - } - } - //entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); + entityInfo.SetValue(userId); + } + else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateUserId)) + { + entityInfo.SetValue(userId); } } //修改 @@ -44,17 +43,7 @@ public class DataBaseContext entityInfo.SetValue(DateTime.Now); else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateUserId)) { - if (oldValue == null || (int)oldValue == 1) - { - try - { - entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); - } - catch - { - } - } - //entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); + entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); } //删除 else if (entityInfo.PropertyName == nameof(IDeleteBasicEntity.IsDeleted)) diff --git a/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs b/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs index 841a3555..669ed58c 100644 --- a/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs +++ b/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs @@ -4,7 +4,6 @@ using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Queries; using SJZY.Track.Domain.VEntities; -using SJZY.Track.Repository.VData.Entitys; namespace SJZY.Track.Repository.Queries; diff --git a/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs index c7e21820..f073f286 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs @@ -6,7 +6,6 @@ using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPush; using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.VEntities; -using SJZY.Track.Repository.VData.Entitys; namespace SJZY.Track.Repository.Repositories; diff --git a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs index 81c704ac..fe25f1d7 100644 --- a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs @@ -1,5 +1,6 @@ using SJZY.Track.Domain; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.VEntities; @@ -13,20 +14,17 @@ public class WarningRepository : BasicRepository, IWarningReposit using var tran = TransactionHelper.GetReadCommitted(); var ruleId = await InsertReturnIdentityAsync(warning); - warning.WarningRules.ForEach(x => x.WarningId = ruleId); + warning.WarningNotifies.ForEach(x => x.WarningId = ruleId); warning.WarningFactors.ForEach(x => x.WarningId = ruleId); + warning.WarningRules.ForEach(x => x.WarningId = ruleId); - await Context.Insertable(warning.WarningRules).ExecuteCommandAsync(); await Context.Insertable(warning.WarningFactors).ExecuteCommandAsync(); + await Context.Insertable(warning.WarningNotifies).ExecuteCommandAsync(); + await Context.Insertable(warning.WarningRules).ExecuteCommandAsync(); tran.Complete(); return ruleId; } - public Task UpdateForewarningAsync(WarningEntity warning) - { - throw new NotImplementedException(); - } - public Task CopyForewarning(int warningId) { throw new NotImplementedException(); @@ -36,40 +34,79 @@ public class WarningRepository : BasicRepository, IWarningReposit { var query = Context.Queryable() .LeftJoin((a, b) => a.SubSystemId == b.Id) + .LeftJoin((a, b, c) => a.CustomerId == c.Id) .WhereIF(input.SystemId.HasValue, (a, b) => a.SubSystemId == input.SystemId) - .WhereIF(!string.IsNullOrEmpty(input.KeyWord), a => a.CustomerName.Contains(input.KeyWord!) || a.Name.Contains(input.KeyWord!)) + .WhereIF(!string.IsNullOrEmpty(input.KeyWord), + (a, b, c) => a.Name.Contains(input.KeyWord!) || c.Name.Contains(input.KeyWord!)) .OrderBy(a => a.UpdateTime, OrderByType.Desc); return query - .Select((a, b) => new WarningPageOutput + .Select((a, b, c) => new WarningPageOutput { Id = a.Id, SubSystem = b.CnName, - Custom = a.CustomerName, + Custom = c.Name, Name = a.Name, UpdateTime = a.UpdateTime }) .ToPagedListAsync(input.PageIndex, input.PageSize); } - - public async Task> GetWarningRuleListAsync(int warningId) + + public async Task> GetWarningRuleListAsync(int warningId) { return await Context.Queryable() .LeftJoin((a, b) => a.StartTrackStatusId == b.Id) .LeftJoin((a, b, c) => a.EndTrackStatusId == c.Id) + .LeftJoin((a, b, c, d) => a.AreaId == d.Id) .Where(a => a.WarningId == warningId) - .Select((a, b, c) => new WarningRuleOutput + .Select((a, b, c, d) => new WarningRuleVo { StartTrackStatus = b.Status, EndTrackStatus = c.Status, + Area = d.Name }, true) .ToListAsync(); } + public async Task UpdateForewarningAsync(WarningEntity warning) + { + using var tran = TransactionHelper.GetReadCommitted(); + + await Context.Updateable(warning).ExecuteCommandAsync(); + await Context.Updateable(warning.WarningNotifies) + .UpdateColumns(x => new { x.NotifyMode, x.NotifyTemplate, x.NotifyUserId, x.UpdateTime, x.UpdateUserId }) + .ExecuteCommandAsync(); + + tran.Complete(); + } + public async Task ModifyTimeSpansAsync(List rules) { return await Context.Updateable(rules) - .UpdateColumns(x => new { x.TotalTimeSpan, x.WarnTimeSpan, x.WarnCount }) + .UpdateColumns(x => new { x.TotalTimeSpan, x.WarnTimeSpan, x.WarnCount, x.UpdateTime, x.UpdateUserId }) .ExecuteCommandAsync(); } + + public async Task TurnWarningAsync(WarningEntity warning) + { + return await Context.Updateable(warning) + .UpdateColumns(x => new { x.IsEnable, x.UpdateTime, x.UpdateUserId }) + .ExecuteCommandAsync() > 0; + } + + public async Task GetByIdAsync(int warningId) + { + var warning = await GetFirstAsync(x => x.Id == warningId); + + if (warning == null) return null; + + warning.WarningFactors = await Context.Queryable() + .Where(x => x.WarningId == warningId) + .ToListAsync(); + warning.WarningNotifies = await Context.Queryable() + .Where(x => x.WarningId == warningId) + .ToListAsync(); + + return warning; + } } \ No newline at end of file From bd8879885bbbe70f3ed262847ce8fe5ef181e54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 15:12:43 +0800 Subject: [PATCH 27/60] =?UTF-8?q?fix=EF=BC=9A=20=E8=B0=83=E6=95=B4area?= =?UTF-8?q?=E7=9A=84=E8=A1=A8=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aggregates/KPIAreaAggregate/RuleAreaEntity.cs | 2 +- .../Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs index 2f404cea..5d43a11a 100644 --- a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; -[SugarTable("t_rule_area", TableDescription = "KPI分区主表")] +[SugarTable("t_area", TableDescription = "KPI分区主表")] public class RuleAreaEntity : IAggregateRoot { /// diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs index 66b28382..5a1b97c7 100644 --- a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; -[SugarTable("t_rule_area_info", TableDescription = "kpi 区域子表")] +[SugarTable("t_area_details", TableDescription = "kpi 区域子表")] public class RuleAreaInfoEntity : IEntity { /// From 45ce7a99491e02459cb2f231cd682f02fe6e7f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 15:34:39 +0800 Subject: [PATCH 28/60] =?UTF-8?q?feat:=20=E8=AE=A2=E5=8D=95=E8=A1=A8?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B7=9E=E7=9C=81=E5=92=8C=E9=82=AE=E7=BC=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit alter table t_order add Postcode varchar(64) null comment '邮编'; alter table t_order add Province varchar(64) null comment '省份'; --- .../Aggregates/OrderAggregate/OrderEntity.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index b04aa76a..d2999e74 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -154,7 +154,19 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 /// [SugarColumn(ColumnName = "DeficiencyTag")] - public int? DeficiencyTag { get; set; } + public int? DeficiencyTag { get; set; } + + /// + /// 邮编 + /// + [SugarColumn(ColumnName = "Postcode")] + public string? Postcode { get; set; } + + /// + /// 州省 + /// + [SugarColumn(ColumnName = "Province")] + public string? Province { get; set; } [SugarColumn(IsIgnore = true)] public List OrderFlights { get; set; } [SugarColumn(IsIgnore = true)] public List OrderTemplates { get; set; } From 0be6d452ee93adb741e217b95f4e87c8ea253eb4 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 15:54:21 +0800 Subject: [PATCH 29/60] =?UTF-8?q?fix=EF=BC=9ACalcRuleList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoMapper/ForewarningMapperProfile.cs | 4 +++- .../Helpers/ForewarningHelper.cs | 14 ++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs index c06978eb..2498dccb 100644 --- a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs @@ -3,6 +3,7 @@ using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; +using Volo.Abp.AutoMapper; namespace SJZY.Track.Application.AutoMapper; @@ -10,7 +11,8 @@ public class ForewarningMapperProfile :Profile { public ForewarningMapperProfile() { - CreateMap(MemberList.None); + CreateMap(MemberList.None) + .Ignore(x => x.WarningFactors); CreateMap(MemberList.None); CreateMap(); CreateMap(MemberList.None); diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index c03be716..cfdc5cfb 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -23,14 +23,14 @@ public class ForewarningHelper { throw new BusinessException(message: "轨迹状态区间或因素列表为空"); } - + var len = statusSpans.Count * factors.Select(f => f.FactorValue.Count).Aggregate((pre, cur) => pre * cur); if (len == 0) { throw new BusinessException(message: "轨迹状态区间或因素列表为空"); } - var rules = new List(len); + var rules = Enumerable.Repeat(new WarningRuleEntity(), len).ToList(); var repeat = len / statusSpans.Count; @@ -39,7 +39,7 @@ public class ForewarningHelper foreach (var factor in factors) { var factorValueCount = factor.FactorValue.Count; - + // repeat梯度下降,与times成反比关系 repeat /= factor.FactorValue.Count; var times = len / repeat / factorValueCount; @@ -52,13 +52,11 @@ public class ForewarningHelper private static void FillStatus(List statusSpans, List rules, int repeat) { - for (var i = 0; i < statusSpans.Count; i++) + var row = 0; + foreach (var span in statusSpans) { - var span = statusSpans[i]; - - for (var j = 0; j < repeat; j++) + for (var i = 0; i < repeat; i++, row++) { - var row = i * repeat + j; rules[row].StartTrackStatusId = span.StartTrackStatusId; rules[row].EndTrackStatusId = span.EndTrackStatusId; } From 86a033288650840b7c9ccfc5aac0d62604d6ae46 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 15:54:21 +0800 Subject: [PATCH 30/60] =?UTF-8?q?fix=EF=BC=9ACalcRuleList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoMapper/ForewarningMapperProfile.cs | 4 +++- .../Helpers/ForewarningHelper.cs | 14 ++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs index c06978eb..2498dccb 100644 --- a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs @@ -3,6 +3,7 @@ using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; +using Volo.Abp.AutoMapper; namespace SJZY.Track.Application.AutoMapper; @@ -10,7 +11,8 @@ public class ForewarningMapperProfile :Profile { public ForewarningMapperProfile() { - CreateMap(MemberList.None); + CreateMap(MemberList.None) + .Ignore(x => x.WarningFactors); CreateMap(MemberList.None); CreateMap(); CreateMap(MemberList.None); diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index c03be716..cfdc5cfb 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -23,14 +23,14 @@ public class ForewarningHelper { throw new BusinessException(message: "轨迹状态区间或因素列表为空"); } - + var len = statusSpans.Count * factors.Select(f => f.FactorValue.Count).Aggregate((pre, cur) => pre * cur); if (len == 0) { throw new BusinessException(message: "轨迹状态区间或因素列表为空"); } - var rules = new List(len); + var rules = Enumerable.Repeat(new WarningRuleEntity(), len).ToList(); var repeat = len / statusSpans.Count; @@ -39,7 +39,7 @@ public class ForewarningHelper foreach (var factor in factors) { var factorValueCount = factor.FactorValue.Count; - + // repeat梯度下降,与times成反比关系 repeat /= factor.FactorValue.Count; var times = len / repeat / factorValueCount; @@ -52,13 +52,11 @@ public class ForewarningHelper private static void FillStatus(List statusSpans, List rules, int repeat) { - for (var i = 0; i < statusSpans.Count; i++) + var row = 0; + foreach (var span in statusSpans) { - var span = statusSpans[i]; - - for (var j = 0; j < repeat; j++) + for (var i = 0; i < repeat; i++, row++) { - var row = i * repeat + j; rules[row].StartTrackStatusId = span.StartTrackStatusId; rules[row].EndTrackStatusId = span.EndTrackStatusId; } From 06d51528b03b5d64431595d3c97f42bff4ee09e5 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 16:00:07 +0800 Subject: [PATCH 31/60] =?UTF-8?q?fix=EF=BC=9A=E8=A1=A8=E5=90=8Dattribute?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aggregates/ForewarningAggregate/WarningFactorEntity.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs index 46d9c4d8..9c342518 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs @@ -2,6 +2,7 @@ using SJZY.Track.Domain.Enums; namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; +[SugarTable("t_warning_factor")] public class WarningFactorEntity : IFullAuditedBasicEntitys, IEntity { /// From c7ae4e9d059c65384e5108318bcfeba42735c4d6 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 16:12:43 +0800 Subject: [PATCH 32/60] =?UTF-8?q?connect=EF=BC=9A=E5=AF=B9=E6=8E=A5?= =?UTF-8?q?=E9=A2=84=E8=AD=A6=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs | 2 ++ .../Aggregates/ForewarningAggregate/WarningNotifyEntity.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index c20ca137..f402f3d1 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -33,6 +33,8 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa LatestTrackPlace = x.LatestTrackPlace, LatestTrackTime = x.LatestTrackTime, LatestTrackTimeZone = x.LatestTrackTimeZone, + ArrivalCountry = x.ArrivalCountry, + ArrivalCity = x.ArrivalCity, }); if (orders.Count == 0) return; diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs index 1b08f86f..1b846469 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs @@ -2,6 +2,7 @@ using SJZY.Track.Domain.Enums; namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; +[SugarTable("t_warning_notify")] public class WarningNotifyEntity : IFullAuditedBasicEntitys, IEntity { /// From 5b4c300baf1694c6eaa54fa3d79ccfdb66062440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 16:13:01 +0800 Subject: [PATCH 33/60] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4=E8=A1=A8?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aggregates/OrderAggregate/OrderEntity.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index d2999e74..05af70fb 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -157,16 +157,16 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot public int? DeficiencyTag { get; set; } /// - /// 邮编 + /// 到达邮编 /// - [SugarColumn(ColumnName = "Postcode")] - public string? Postcode { get; set; } + [SugarColumn(ColumnName = "ArrivalPostCode")] + public string? ArrivalPostCode { get; set; } /// - /// 州省 + /// 到达州省 /// - [SugarColumn(ColumnName = "Province")] - public string? Province { get; set; } + [SugarColumn(ColumnName = "ArrivalProvince")] + public string? ArrivalProvince { get; set; } [SugarColumn(IsIgnore = true)] public List OrderFlights { get; set; } [SugarColumn(IsIgnore = true)] public List OrderTemplates { get; set; } From d5135249f7c6952c11daf146ca68c7ae3ad91985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 16:20:07 +0800 Subject: [PATCH 34/60] =?UTF-8?q?fix:=20=20=E8=B0=83=E6=95=B4order=20?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aggregates/OrderAggregate/OrderEntity.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index 05af70fb..4aefeac6 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -133,19 +133,19 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot public string? LeavePort { get; set; } /// - /// 起运港口 + /// 货物类型 /// [SugarColumn(ColumnName = "CargoType")] public string? CargoType { get; set; } /// - /// 起运港口 + /// 是否中转 /// - [SugarColumn(ColumnName = "IsTransfer")] - public bool? IsTransfer { get; set; } + [SugarColumn(ColumnName = "IsTransit")] + public bool? IsTransit { get; set; } /// - /// 起运港口 + /// 产品编码 /// [SugarColumn(ColumnName = "ProductCode")] public string? ProductCode { get; set; } From f00805437d91503ee9338020df920d91fc50e6ce Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 17:12:46 +0800 Subject: [PATCH 35/60] =?UTF-8?q?connect=EF=BC=9A=E9=A2=84=E8=AD=A6?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=88=97=E8=A1=A8=E5=8A=A8=E6=80=81=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E5=A5=BD=E7=BB=99=E5=88=B0=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...TrackChangeAfterUpdateOrderEventHandler.cs | 113 +++++++++++------- .../Helpers/ForewarningHelper.cs | 55 ++++++++- .../ForewarningNotifyService.cs | 2 +- .../ForewarningServices/ForewarningService.cs | 19 ++- .../Dtos/Forewarning/ForewarningOrderModel.cs | 9 +- .../Dtos/Forewarning/ForewarningRuleItem.cs | 6 +- .../Forewarning/IForewarningFactorValue.cs | 6 +- 7 files changed, 150 insertions(+), 60 deletions(-) diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index f402f3d1..8293c2fb 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -13,7 +13,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa private readonly IOrderRepository _orderRepository; private readonly IForewarningNotifyService _forewarningNotifyService; - public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, + public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, IForewarningNotifyService forewarningNotifyService) { _orderRepository = orderRepository; @@ -23,19 +23,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] public async Task ConsumerAsync(TrackChangeAfterUpdateOrderEvent @event) { - var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id), - x => new OrderEntity - { - Id = x.Id, - IsCompleted = x.IsCompleted, - LatestTrackContent = x.LatestTrackContent, - LatestTrackEnContent = x.LatestTrackEnContent, - LatestTrackPlace = x.LatestTrackPlace, - LatestTrackTime = x.LatestTrackTime, - LatestTrackTimeZone = x.LatestTrackTimeZone, - ArrivalCountry = x.ArrivalCountry, - ArrivalCity = x.ArrivalCity, - }); + var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id), x => MapOrderSummary(x)); if (orders.Count == 0) return; @@ -70,41 +58,78 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, x.LatestTrackTimeZone }); + + // 预警计算 + WarningCalculationAsync(orders); } - private ForewarningOrderModel OrderToForewarningOrderModel(OrderEntity order) -{ - return new ForewarningOrderModel + private Task WarningCalculationAsync(List orders) { - Id = order.Id, - Track = DetermineTrackBasedOnOrderDetails(order), - SystemId = order.SubSystemId, - CustomerId = order.CustomId, - CargoType = order.CargoType, - Month = order.CreateTime.Month, - Area = DetermineAreaBasedOnOrderDetails(order), - IsTransit = order.IsTransfer, - DeparturePort = order.LeavePort, - ProductCode = order.ProductCode - }; -} + var forewarningOrderModels = orders.Select(OrderToForewarningOrderModel).ToList(); + + return Task.CompletedTask; + } + + private OrderEntity MapOrderSummary(OrderEntity x) + { + return new OrderEntity + { + Id = x.Id, + + // 轨迹 + IsCompleted = x.IsCompleted, + LatestTrackContent = x.LatestTrackContent, + LatestTrackEnContent = x.LatestTrackEnContent, + LatestTrackPlace = x.LatestTrackPlace, + LatestTrackTime = x.LatestTrackTime, + LatestTrackTimeZone = x.LatestTrackTimeZone, + + // 因素 + CargoType = x.CargoType, + CreateTime = x.CreateTime, + ArrivalCountry = x.ArrivalCountry, + ArrivalProvince = x.ArrivalProvince, + ArrivalCity = x.ArrivalCity, + ArrivalPostCode = x.ArrivalPostCode, + IsTransit = x.IsTransit, + LeavePort = x.LeavePort, + ProductCode = x.ProductCode + }; + } + + private ForewarningOrderModel OrderToForewarningOrderModel(OrderEntity order) + { + return new ForewarningOrderModel + { + Id = order.Id, + Track = DetermineTrackBasedOnOrderDetails(order), + SystemId = order.SubSystemId, + CustomerId = order.CustomId, + CargoType = order.CargoType, + Month = order.CreateTime.Month, + Area = DetermineAreaBasedOnOrderDetails(order), + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode + }; + } // Placeholder methods for deriving or converting values. You'll need to implement these based on your specific logic. -private int DetermineTrackBasedOnOrderDetails(OrderEntity order) -{ - // Implement logic to determine Track - return default; -} + private int DetermineTrackBasedOnOrderDetails(OrderEntity order) + { + // Implement logic to determine Track + return default; + } -private int? DetermineMonthBasedOnOrderDetails(OrderEntity order) -{ - // Implement logic to determine Month - return default; -} + private int? DetermineMonthBasedOnOrderDetails(OrderEntity order) + { + // Implement logic to determine Month + return default; + } -private int? DetermineAreaBasedOnOrderDetails(OrderEntity order) -{ - // Implement logic to determine Area - return default; -} + private int? DetermineAreaBasedOnOrderDetails(OrderEntity order) + { + // Implement logic to determine Area + return default; + } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index cfdc5cfb..c85ef3db 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -1,3 +1,5 @@ +using System.Dynamic; +using Nest; using Newtonsoft.Json.Linq; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Dtos.Forewarning; @@ -30,7 +32,7 @@ public class ForewarningHelper throw new BusinessException(message: "轨迹状态区间或因素列表为空"); } - var rules = Enumerable.Repeat(new WarningRuleEntity(), len).ToList(); + var rules = Enumerable.Range(0, len).Select(_ => new WarningRuleEntity()).ToList(); var repeat = len / statusSpans.Count; @@ -41,7 +43,7 @@ public class ForewarningHelper var factorValueCount = factor.FactorValue.Count; // repeat梯度下降,与times成反比关系 - repeat /= factor.FactorValue.Count; + repeat /= factorValueCount; var times = len / repeat / factorValueCount; FillFactor(factor, rules, repeat, times); } @@ -184,4 +186,53 @@ public class ForewarningHelper }).ToList() }; } + + public static List DynamicCalcRuleList(List rules, List factors) + { + var dynamicList = new List(); + + foreach (var rule in rules) + { + dynamic dynamicRule = new ExpandoObject(); + var dynamicRuleDict = (IDictionary)dynamicRule; + + dynamicRuleDict[nameof(Id)] = rule.Id; + dynamicRuleDict[nameof(rule.StartTrackStatus)] = rule.StartTrackStatus; + dynamicRuleDict[nameof(rule.EndTrackStatus)] = rule.EndTrackStatus; + + foreach (var factor in factors) + { + switch (factor) + { + case RuleFactorType.CargoType: + dynamicRuleDict[nameof(rule.CargoType)] = rule.CargoType; + break; + case RuleFactorType.Months: + dynamicRuleDict[nameof(rule.Months)] = rule.Months; + break; + case RuleFactorType.Areas: + dynamicRuleDict[nameof(rule.Area)] = rule.Area; + break; + case RuleFactorType.IsTransit: + dynamicRuleDict[nameof(rule.IsTransit)] = rule.IsTransit; + break; + case RuleFactorType.LeavePort: + dynamicRuleDict[nameof(rule.LeavePort)] = rule.LeavePort; + break; + case RuleFactorType.ProductCode: + dynamicRuleDict[nameof(rule.ProductCode)] = rule.ProductCode; + break; + default: + throw new BusinessException(message: $"不支持的因素:{factor}"); + } + } + + dynamicRuleDict[nameof(rule.TotalTimeSpan)] = rule.TotalTimeSpan; + dynamicRuleDict[nameof(rule.WarnTimeSpan)] = rule.WarnTimeSpan; + dynamicRuleDict[nameof(rule.WarnCount)] = rule.WarnCount; + dynamicList.Add(dynamicRule); + } + + return dynamicList; + } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index 3beac40f..8aa91e75 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -221,7 +221,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep case RuleFactorType.CargoType: return rule.CargoType; case RuleFactorType.LeavePort: - return rule.DeparturePort; + return rule.LeavePort; case RuleFactorType.Months: return rule.Month.HasValue ? rule.Month.Value.ToString() : throw new Exception("月份不能为空"); case RuleFactorType.ProductCode: diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index 6d8a61d4..abe4f846 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -3,6 +3,7 @@ using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -38,6 +39,13 @@ public class ForewarningService : ApplicationService public async Task CreateWarning(CreateWarningInput input) { var warning = ObjectMapper.Map(input); + + if (await _warningRepository.IsAnyAsync(x => + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.Name == warning.Name)) + { + throw new BusinessException(message: "该子系统下的客户已经存在一个同名预警: " + warning.Name); + } + warning.WarningRules = ForewarningHelper.CalcRuleList(input.TrackStatusSpans, input.WarningFactors); warning.WarningFactors = ForewarningHelper.MapFactorEntities(input.WarningFactors); warning.WarningNotifies = ForewarningHelper.MapNotifyEntities(input); @@ -126,18 +134,21 @@ public class ForewarningService : ApplicationService return await _warningRepository.TurnWarningAsync(warning); } - + /// /// 查询预警规则列表 /// /// 预警规则id + /// /// [HttpGet("GetWarningRuleList")] - public async Task> GetWarningRuleListAsync([Required] int warningId) + public async Task> GetWarningRuleListAsync([Required] int warningId, [FromServices] IBasicQuery factorQuery) { + var factors = await factorQuery.GetListAsync(x => x.WarningId == warningId, x => x.Type); var rules = await _warningRepository.GetWarningRuleListAsync(warningId); - - return rules; + + var dynamicList = ForewarningHelper.DynamicCalcRuleList(rules, factors); + return dynamicList; } /// diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs index c44d633f..8dbd7ae5 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs @@ -16,7 +16,7 @@ public class ForewarningOrderModel:IForewarningFactorValue public int CustomerId { get; set; } - public string CargoType { get; set; } + public string? CargoType { get; set; } public int? Month { get; set; } @@ -24,7 +24,10 @@ public class ForewarningOrderModel:IForewarningFactorValue public bool? IsTransit { get; set; } - public string DeparturePort { get; set; } + /// + /// 起运港 + /// + public string? LeavePort { get; set; } - public string ProductCode { get; set; } + public string? ProductCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs index ef550296..9e03f6c2 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs @@ -13,12 +13,12 @@ public record struct ForewarningRuleItem:IForewarningFactorValue public int Count { get; set; } public int TrackStart { get; set; } public int TrackEnd { get; set; } - public string CargoType { get; set; } + public string? CargoType { get; set; } public int? Month { get; set; } public int? Area { get; set; } public bool? IsTransit { get; set; } - public string DeparturePort { get; set; } - public string ProductCode { get; set; } + public string? LeavePort { get; set; } + public string? ProductCode { get; set; } public string Conect { get; set; } diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs index 4ace20ac..11dae2ce 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs @@ -2,7 +2,7 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public interface IForewarningFactorValue { - public string CargoType { get; set; } + public string? CargoType { get; set; } public int? Month { get; set; } @@ -10,7 +10,7 @@ public interface IForewarningFactorValue public bool? IsTransit { get; set; } - public string DeparturePort { get; set; } + public string? LeavePort { get; set; } - public string ProductCode { get; set; } + public string? ProductCode { get; set; } } \ No newline at end of file From 4a0df97333ac2de7c1c293410e3e292a79bb1d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 17:23:00 +0800 Subject: [PATCH 36/60] =?UTF-8?q?feat:=20=E8=BD=A8=E8=BF=B9=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/TrackNode/TrackNodeInput.cs | 29 ++++ .../Dtos/TrackStatus/QueryTrackNodeRequest.cs | 14 ++ .../AutoMapper/TrackNodeMapperProfile.cs | 20 +++ ...TrackChangeAfterUpdateOrderEventHandler.cs | 2 +- .../TrackNodeServices/TrackNodeService.cs | 132 ++++++++++++++++++ .../ITrackNodeRepository.cs | 27 ++++ .../TrackNodeAggregate/TrackNodeEntity.cs | 32 +++++ .../Dtos/TrackNode/TrackNodeDicDto.cs | 19 +++ .../Dtos/TrackNode/TrackNodeDto.cs | 56 ++++++++ .../Dtos/TrackNode/TrackNodePageDto.cs | 14 ++ .../Repositories/TrackNodeRepository.cs | 53 +++++++ 11 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs create mode 100644 src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs create mode 100644 src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs create mode 100644 src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs create mode 100644 src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs create mode 100644 src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs create mode 100644 src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs create mode 100644 src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs new file mode 100644 index 00000000..8e313589 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackNode; + +public class EditTrackNodeInput +{ + /// + /// 操作类型 + /// + public OptionType Options { get; set; } + + /// + /// 轨迹节点id,创建不用填 + /// + public long Id { get; set; } + + /// + /// 系统id + /// + public int SystemId { get; set; } + + /// + /// 节点名称 + /// + public string Name { get; set; } + + /// + /// 节点英文名称 + /// + public string EnName { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs new file mode 100644 index 00000000..f7903f71 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackStatus; + +public class QueryTrackNodeRequest:PageInfoInput +{ + /// + /// 关键字,节点中文和英文 + /// + public string? KeyWord { get; set; } + + /// + /// 子系统id + /// + public long? SystemId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs new file mode 100644 index 00000000..af8699e0 --- /dev/null +++ b/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs @@ -0,0 +1,20 @@ +using AutoMapper; +using SJZY.Track.Application.Contract.Dtos.TrackNode; +using SJZY.Track.Application.Contract.Dtos.TrackStatus; +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; +using SJZY.Track.Domain.Dtos.TrackNode; + +namespace SJZY.Track.Application.AutoMapper; + +public class TrackNodeMapperProfile :Profile +{ + public TrackNodeMapperProfile() + { + CreateMap(); + CreateMap(MemberList.None) + .ForMember(val => val.NodeName, opt => opt.MapFrom(src => src.Name)) + .ForMember(val => val.NodeEnName, opt => opt.MapFrom(src => src.EnName)) + .ForMember(val => val.SubSystemId, opt => opt.MapFrom(src => src.SystemId)); + + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index f402f3d1..b6632dea 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -83,7 +83,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa CargoType = order.CargoType, Month = order.CreateTime.Month, Area = DetermineAreaBasedOnOrderDetails(order), - IsTransit = order.IsTransfer, + IsTransit = order.IsTransit, DeparturePort = order.LeavePort, ProductCode = order.ProductCode }; diff --git a/src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs b/src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs new file mode 100644 index 00000000..7b8f3d3a --- /dev/null +++ b/src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs @@ -0,0 +1,132 @@ +using Microsoft.Extensions.Localization; +using SJZY.Track.Application.Contract.Dtos.TrackNode; +using SJZY.Track.Application.Contract.Dtos.TrackStatus; +using SJZY.Track.Application.Localization; +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Dtos.TrackNode; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.TrackNodeServices +{ + /// + /// 轨迹节点服务 + /// + [ApiExplorerSettings(GroupName = "轨迹节点")] + [Route("/Track/Node")] + public class TrackNodeService : ApplicationService, ITransientDependency + { + private readonly ITrackStatusRepository _trackStatusRepository; + private readonly ITrackNodeRepository _trackNodeRepository; + + public TrackNodeService( + ITrackNodeRepository trackNodeRepository, ITrackStatusRepository trackStatusRepository) + { + this._trackNodeRepository = trackNodeRepository; + _trackStatusRepository = trackStatusRepository; + } + + /// + /// 轨迹节点编辑 + /// + /// + [HttpPost("Edit")] + public async Task EditAsync(EditTrackNodeInput input) + { + return input.Options switch + { + OptionType.新增 => await AddAsync(input), + OptionType.修改 => await UpdateAsync(input), + OptionType.删除 => await DeleteAsync(input), + _ => throw new BusinessException(message: "当前操作动作不合法") + }; + } + + /// + /// 获取分页轨迹节点 + /// + /// + /// + [HttpPost("GetList")] + public async Task> GetPageTrackNode(QueryTrackNodeRequest input) + { + var queryParam = ObjectMapper.Map(input); + var resultDto = await _trackNodeRepository.GetPageList(queryParam); + return resultDto; + } + + /// + /// 获取分页轨迹字典,下拉框用的 + /// + /// + /// + [HttpPost("GetTrackNodeOption")] + public async Task> GetTrackNodeOption(QueryTrackNodeRequest input) + { + var queryParam = ObjectMapper.Map(input); + var resultDto = await _trackNodeRepository.GetPageDicList(queryParam); + return resultDto; + } + + #region 私有方法 + + private async Task AddAsync(EditTrackNodeInput input) + { + #region 业务校验 + var trackNodesEntitys = await _trackNodeRepository.GetListAsync(a => + a.SubSystemId == input.SystemId && (a.NodeName == input.Name || a.NodeEnName == input.EnName)); + if (trackNodesEntitys.Any()) + { + var trackNodeName = trackNodesEntitys.FirstOrDefault(a => a.NodeName == input.Name); + if (trackNodeName != null) + { + throw new BusinessException(message: "该子系统下节点名称已存在"); + } + var trackNodeEnName = trackNodesEntitys.FirstOrDefault(a => a.NodeEnName == input.EnName); + if (trackNodeEnName != null) + { + throw new BusinessException(message: "该子系统下节点英文名称已存在"); + } + } + #endregion + + var entity = ObjectMapper.Map(input); + var isTrue = await _trackNodeRepository.InsertAsync(entity); + + return new UnifyResultDto("200", "新增成功", isTrue); + } + + private async Task UpdateAsync(EditTrackNodeInput input) + { + #region 业务校验 + + var trackNodesEntitys = await _trackNodeRepository.GetFirstAsync(a => a.Id == input.Id); + if (trackNodesEntitys == null) + { + return new UnifyResultDto("200", "没有找到数据,更新失败", false); + } + + #endregion + + trackNodesEntitys.NodeEnName = input.EnName; + trackNodesEntitys.NodeName = input.Name; + var isTrue = await _trackNodeRepository.UpdateAsync(trackNodesEntitys); + + return new UnifyResultDto("200", "修改成功", isTrue); + } + + private async Task DeleteAsync(EditTrackNodeInput input) + { + var trackStatus = await _trackStatusRepository.GetFirstAsync(val => val.Node == input.Id && val.SubSystemId == input.SystemId); + if(trackStatus!=null) + { + return new UnifyResultDto("200", "删除失败,该节点已被使用", false); + } + + var rows = await _trackNodeRepository.DeleteById(input.Id); + return new UnifyResultDto("200", "删除成功", rows>0); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs new file mode 100644 index 00000000..10d1cb70 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs @@ -0,0 +1,27 @@ +using SJZY.Track.Domain.Dtos.TrackNode; + +namespace SJZY.Track.Domain.Aggregates.TrackNodeAggregate; + +public interface ITrackNodeRepository:IBasicRepository +{ + /// + /// 分页查询 + /// + /// + /// + Task> GetPageList(TrackNodePageDto queryParam); + + /// + /// 分页查询字典 + /// + /// + /// + Task> GetPageDicList(TrackNodePageDto queryParam); + + /// + /// 删除 + /// + /// + /// + Task DeleteById(long inputId); +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs new file mode 100644 index 00000000..c17ef2c2 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs @@ -0,0 +1,32 @@ +namespace SJZY.Track.Domain.Aggregates.TrackNodeAggregate; + +/// +/// 轨迹节点主表 +/// +[SugarTable("t_track_node", TableDescription = "轨迹节点主表")] +public class TrackNodeEntity : IFullAuditedBasicEntitys, IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")] + public long Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId", ColumnDescription = "子系统id")] + public int SubSystemId { get; set; } + + /// + /// 节点名称 + /// + [SugarColumn(ColumnName = "NodeName", Length = 32, ColumnDescription = "节点名称")] + public string? NodeName { get; set; } + + /// + /// 节点英文名称 + /// + [SugarColumn(ColumnName = "NodeEnName", Length = 32, ColumnDescription = "节点英文名称")] + public string? NodeEnName { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs new file mode 100644 index 00000000..8402e103 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Domain.Dtos.TrackNode; + +public class TrackNodeDicDto +{ + /// + /// 节点id + /// + public long Id { get; set; } + + /// + /// 名称 + /// + public string NodeName { get; set; } + + /// + /// 名称 + /// + public string EnName { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs new file mode 100644 index 00000000..185f432f --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs @@ -0,0 +1,56 @@ +namespace SJZY.Track.Domain.Dtos.TrackNode; + +/// +/// 轨迹节点主表 DTO +/// +public class TrackNodeDto +{ + /// + /// 自增主键 + /// + public long Id { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } + + /// + /// 节点英文名称 + /// + public string? NodeEnName { get; set; } + + /// + /// 是否删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 创建人id + /// + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + public int? UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdateTime { get; set; } + + public string? CreateUserName { get; set; } + + public string? UpdateUserName { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs new file mode 100644 index 00000000..059e92f2 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.TrackNode; + +public class TrackNodePageDto:PageInfoInput +{ + /// + /// 关键字,节点中文和英文 + /// + public string? KeyWord { get; set; } + + /// + /// 子系统id + /// + public long? SystemId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs new file mode 100644 index 00000000..be340230 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs @@ -0,0 +1,53 @@ +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; +using SJZY.Track.Domain.Dtos.TrackNode; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Repositories; + +public class TrackNodeRepository: BasicRepository,ITrackNodeRepository,IScopedDependency +{ + public async Task> GetPageList(TrackNodePageDto queryParam) + { + var result = await Context.Queryable() + .LeftJoin((t,u1)=>t.CreateUserId==u1.Id) + .LeftJoin((t,u1,u2)=>t.UpdateUserId==u2.Id) + .Where((t,u1,u2)=>!t.IsDeleted&&!u1.IsDeleted&&!u2.IsDeleted) + .WhereIF(!string.IsNullOrEmpty(queryParam.KeyWord), (t,u1,u2)=>t.NodeName!.Contains(queryParam.KeyWord)||t.NodeEnName!.Contains(queryParam.KeyWord)) + .WhereIF(queryParam.SystemId.HasValue,(t,u1,u2)=>t.SubSystemId == queryParam.SystemId.Value) + .Select((t, u1, u2) =>new TrackNodeDto() + { + Id = t.Id, + NodeName = t.NodeName, + NodeEnName = t.NodeEnName, + SubSystemId = t.SubSystemId, + UpdateTime = t.UpdateTime, + CreateTime = t.CreateTime, + UpdateUserId = t.UpdateUserId, + UpdateUserName = u2.Name, + CreateUserName = u1.Name + }).ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize); + + return result; + } + + public async Task> GetPageDicList(TrackNodePageDto queryParam) + { + var result = await Context.Queryable() + .Where((t)=>!t.IsDeleted) + .WhereIF(!string.IsNullOrEmpty(queryParam.KeyWord), (t)=>t.NodeName!.Contains(queryParam.KeyWord)||t.NodeEnName!.Contains(queryParam.KeyWord)) + .WhereIF(queryParam.SystemId.HasValue,(t)=>t.SubSystemId == queryParam.SystemId.Value) + .Select(t =>new TrackNodeDicDto() + { + Id = t.Id, + NodeName = t.NodeName, + EnName = t.NodeEnName, + }).ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize); + + return result; + } + + public Task DeleteById(long inputId) + { + return Context.Deleteable().Where(val=>val.Id==inputId).ExecuteCommandAsync(); + } +} \ No newline at end of file From 2f172f43c0e9aa9b905573183904d0729f61e445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 17:56:03 +0800 Subject: [PATCH 37/60] =?UTF-8?q?feat:=20=E8=BD=A8=E8=BF=B9=E6=98=A0?= =?UTF-8?q?=E5=B0=84-=E6=96=B0=E5=A2=9E=E6=8B=89=E5=8F=96=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E5=A2=9E=E5=8A=A0=E5=AD=97=E6=AE=B5=EF=BC=9A=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E6=8B=89=E5=8F=96=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/TrackPull/EditTrackPullConfigInput.cs | 6 +++++- .../Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs index f60beeb4..3a6b51dc 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs @@ -70,7 +70,11 @@ public class EditTrackPullConfigInput public string? OrderPath { get; set; } /// - /// 轨迹明细路径 /// public string? TrackDetailsPath { get; set; } + + /// + /// 轨迹内容code + /// + public string? TrackContentCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs index 4c6d7ed7..4e016b17 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs @@ -35,4 +35,9 @@ public class TrackPullConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "SubSystemId")] public int SubSystemId { get; set; } + + /// + /// 轨迹内容code + /// + public string? TrackContentCode { get; set; } } \ No newline at end of file From dd8a8065ccaf3fc95f7e196c4dcf821204c95ee6 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 26 Jul 2024 17:57:58 +0800 Subject: [PATCH 38/60] temp --- .../Services/IForewarningNotifyService.cs | 2 +- ...TrackChangeAfterUpdateOrderEventHandler.cs | 41 ++++++++----------- .../Helpers/ForewarningHelper.cs | 1 - .../ForewarningNotifyService.cs | 12 ++---- .../Dtos/Forewarning/ForewarningOrderModel.cs | 4 +- 5 files changed, 23 insertions(+), 37 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs index f76891a1..58dcd995 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs @@ -13,7 +13,7 @@ public interface IForewarningNotifyService /// /// 预警订单模型。 /// 创建操作的结果,以整数形式返回。 - Task CreateForewarningNotify(ForewarningOrderModel order); + Task WarningCalculateAsync(List order); /// /// 删除预警通知。 diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 8293c2fb..859fb666 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -60,14 +60,20 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }); // 预警计算 - WarningCalculationAsync(orders); - } - - private Task WarningCalculationAsync(List orders) - { - var forewarningOrderModels = orders.Select(OrderToForewarningOrderModel).ToList(); - - return Task.CompletedTask; + var warningOrders = orders.Select(order => new ForewarningOrderModel + { + Id = order.Id, + TrackStatusId = @event.TrackStatusId, + SubSystemId = order.SubSystemId, + CustomerId = order.CustomId, + CargoType = order.CargoType, + Month = order.CreateTime.Month, + Area = DetermineAreaBasedOnOrderDetails(order), + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode + }).ToList(); + _forewarningNotifyService.WarningCalculateAsync(warningOrders); } private OrderEntity MapOrderSummary(OrderEntity x) @@ -75,6 +81,8 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa return new OrderEntity { Id = x.Id, + SubSystemId = x.SubSystemId, + CustomId = x.CustomId, // 轨迹 IsCompleted = x.IsCompleted, @@ -97,23 +105,6 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }; } - private ForewarningOrderModel OrderToForewarningOrderModel(OrderEntity order) - { - return new ForewarningOrderModel - { - Id = order.Id, - Track = DetermineTrackBasedOnOrderDetails(order), - SystemId = order.SubSystemId, - CustomerId = order.CustomId, - CargoType = order.CargoType, - Month = order.CreateTime.Month, - Area = DetermineAreaBasedOnOrderDetails(order), - IsTransit = order.IsTransit, - LeavePort = order.LeavePort, - ProductCode = order.ProductCode - }; - } - // Placeholder methods for deriving or converting values. You'll need to implement these based on your specific logic. private int DetermineTrackBasedOnOrderDetails(OrderEntity order) { diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index c85ef3db..6b572c44 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -6,7 +6,6 @@ using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.Enums; -using SqlSugar; namespace SJZY.Track.Application.Helpers; diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index 8aa91e75..c097ff7c 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -31,13 +31,9 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep /// /// 创建预警通知需要的订单信息 /// 创建的通知总量,0表示没有规则 - public async Task CreateForewarningNotify(ForewarningOrderModel order) + public async Task WarningCalculateAsync(List order) { - var rules = GetRule(order); - if (rules == null || rules.Count == 0) - return 0; - - return await ExecuteRule(rules, order.Id); + throw new NotImplementedException(); } /// @@ -107,7 +103,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep /// private List GetRule(ForewarningOrderModel order) { - if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SystemId), out var factors)) + if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SubSystemId), out var factors)) { return null; } @@ -120,7 +116,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep if (!_ruleGroupDict.TryGetValue(item, out var rules)) continue; - var allRules = rules.Where(val => val.TrackStart <= order.Track && val.TrackEnd >= order.Track); + var allRules = rules.Where(val => val.TrackStart <= order.TrackStatusId && val.TrackEnd >= order.TrackStatusId); result.AddRange(allRules); } diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs index 8dbd7ae5..3767abcb 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs @@ -10,9 +10,9 @@ public class ForewarningOrderModel:IForewarningFactorValue /// /// 当前轨迹状态 /// - public int Track { get; set; } + public int TrackStatusId { get; set; } - public int SystemId { get; set; } + public int SubSystemId { get; set; } public int CustomerId { get; set; } From 9494ca2cb79111b6e47498aec7f885fa4425c05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Fri, 26 Jul 2024 21:04:19 +0800 Subject: [PATCH 39/60] =?UTF-8?q?feat:=20=20=E8=BD=A8=E8=BF=B9=E6=98=A0?= =?UTF-8?q?=E5=B0=84-=E6=96=B0=E5=A2=9E=E6=8B=89=E5=8F=96=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E5=A2=9E=E5=8A=A0=E5=AD=97=E6=AE=B5=EF=BC=9A=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E6=8B=89=E5=8F=96=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/TrackPull/TrackPullParamConfigDto.cs | 5 +++ .../Events/OrderIdentifier.cs | 2 + .../TrackChangeAfterUpdateOrderEvent.cs | 5 +++ ...ChangeBottomLineUpdateOrderEventHandler.cs | 5 ++- ...TrackChangeAfterUpdateOrderEventHandler.cs | 7 ++++ .../EventHandlers/TrackUpsertEventHandler.cs | 40 +++++++++++++++++-- .../Aggregates/OrderAggregate/OrderEntity.cs | 8 +++- .../TrackPushPullParamsConfigEntity.cs | 6 +++ .../Dtos/Order/OrderTransportDto.cs | 10 +++++ .../GetTrackPullConfigDetailOutputVO.cs | 5 +++ .../Queries/IProvideQueries.cs | 7 ++++ .../Queries/ProvideQueries.cs | 16 +++++++- .../Repositories/OrderRepository.cs | 5 ++- .../Repositories/TrackPullConfigRepository.cs | 3 +- 14 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs index 79af5185..c4f65d0b 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs @@ -46,4 +46,9 @@ public class TrackPullParamConfigDto /// 轨迹明细数组路径 /// public string TrackDetailsPath { get; set; } = null!; + + /// + /// 轨迹内容代码 + /// + public string? TrackContentCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs b/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs index 158e64b1..48186952 100644 --- a/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs +++ b/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs @@ -7,4 +7,6 @@ public struct OrderIdentifier public int OrderType { get; set; } public int CustomId { get; set; } + + public bool IsTrigger { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs index b52a95a3..526febd8 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -41,4 +41,9 @@ public class TrackChangeAfterUpdateOrderEvent /// 轨迹时区 /// public float TrackTimeZone { get; set; } + + /// + /// 根据配置规则,标记拉取时需要的订单Id + /// + public int[] TriggerPullOrderIds { get; set; } = Array.Empty(); } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs index 0365727d..cccaf7eb 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs @@ -6,6 +6,9 @@ using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.CAP.EventHandlers; +/// +/// 拉去轨迹后,执行了兜底操作还是失败的标记操作 +/// public class PullChangeBottomLineUpdateOrderEventHandler :ITransientDependency, ICapSubscribe { private readonly IOrderRepository _orderRepository; @@ -18,6 +21,6 @@ public class PullChangeBottomLineUpdateOrderEventHandler :ITransientDependency, [CapSubscribe(GlobalConst.PullChangeBottomLineUpdateOrderSubscribe)] public async Task ConsumerAsync(PullChangeBottomLineUpdateOrderEvent @event) { - await _orderRepository.UpdateBatchIdsAsync(@event.OrderIds, @event.DeficiencyTagValue); + var rows =await _orderRepository.UpdateBatchIdsAsync(@event.OrderIds, @event.DeficiencyTagValue); } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 859fb666..f5766880 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -28,6 +28,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa if (orders.Count == 0) return; var updateOrders = new List(); + foreach (var order in orders) { if (order.LatestTrackContent != @event.TrackContent) @@ -45,6 +46,12 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa order.IsCompleted = @event.IsCompleted; } + // 触发拉取节点 + if (@event.TriggerPullOrderIds.Contains(order.Id)) + { + order.IsTriggerPull = 1; + } + order.LatestTrackContent = @event.TrackContent; order.LatestTrackEnContent = @event.TrackEnContent; order.LatestTrackPlace = @event.TrackPlace; diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index baa3d8b3..cee1dc82 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -2,11 +2,14 @@ using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; +using OrderIdentifier = SJZY.Track.Application.Contract.Events.OrderIdentifier; namespace SJZY.Track.Application.CAP.EventHandlers; @@ -16,14 +19,16 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe private readonly IProvideQueries _provideQueries; private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly ICapPublisher _capPublisher; + private readonly ITrackPullCacheService _trackPullCacheService; public TrackUpsertEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher, - IProvideQueries provideQueries, ITrackDetailsRepository trackDetailsRepository) + IProvideQueries provideQueries, ITrackDetailsRepository trackDetailsRepository, ITrackPullCacheService trackPullCacheService) { _orderRepository = orderRepository; _capPublisher = capPublisher; _provideQueries = provideQueries; _trackDetailsRepository = trackDetailsRepository; + _trackPullCacheService = trackPullCacheService; } [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] @@ -100,7 +105,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } } } - + private async Task HandleTrackAsync(TrackUpsertEvent @event, List canNextOrderIds) { var content = await _provideQueries.GetTrackContentAsync(@event.SubSystemId, @event.TrackCode); @@ -114,7 +119,9 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var trackContents = await _provideQueries.MatchTrackContentAsync(newOrderIds, @event.TrackCode); var insertTracks = new List(); + var triggerPullOrder = new List(); + var providerDic=await GetProviderDic(orderIds); foreach (var order in @event.OrderIdentifiers) { var track = tracks.FirstOrDefault(x => x.OrderId == order.OrderId); @@ -170,13 +177,24 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } canNextOrderIds.Add(order.OrderId); + + if(!providerDic.TryGetValue(order.OrderId,out var provider)) + continue; + + var config = + await _trackPullCacheService.GetPullParamWithContentConfigAsync(provider.SubSystemId, + provider.ServiceProviderId); + if (config!=null && config.ParamConfig!=null && config.ParamConfig.TrackContentCode == @event.TrackCode) + { + triggerPullOrder.Add(order.OrderId); + } } if (canNextOrderIds.Count == 0) return; // 批量add to es await _trackDetailsRepository.AddManyAsync(insertTracks); - + // 触发订单主表更新事件(异步) await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe, new TrackChangeAfterUpdateOrderEvent @@ -188,7 +206,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe TrackStatusId = content.TrackStatusId, TrackPlace = @event.TrackPlace, TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone + TrackTimeZone = @event.TrackTimeZone, + TriggerPullOrderIds = triggerPullOrder.ToArray() }); // 触发轨迹推送事件(异步) @@ -215,4 +234,17 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); } } + + /// + /// 获取服务商字典 + /// + /// + /// + private async Task> GetProviderDic(int[] orderIds) + { + var providerList = await _provideQueries.FindOrderWithServiceProviderAsync(orderIds); + return providerList.GroupBy(val => val.OrderId) + .ToDictionary(val => val.Key, val => val.First()); + } + } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index 4aefeac6..51e8d0e6 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -167,7 +167,13 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "ArrivalProvince")] public string? ArrivalProvince { get; set; } - + + /// + /// 是否触发拉取,1表示触发 + /// + [SugarColumn(ColumnName = "IsTriggerPull")] + public short? IsTriggerPull { get; set; } + [SugarColumn(IsIgnore = true)] public List OrderFlights { get; set; } [SugarColumn(IsIgnore = true)] public List OrderTemplates { get; set; } diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs index 59ea07e1..9687307f 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs @@ -89,4 +89,10 @@ public class TrackPushPullParamsConfigEntity : IFullAuditedBasicEntitys, IEntity /// [SugarColumn(ColumnName = "ExpandFieldsName")] public string? ExpandFieldsName { get; set; } + + /// + /// 轨迹内容代码 + /// + [SugarColumn(ColumnName = "TrackContentCode")] + public string? TrackContentCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs new file mode 100644 index 00000000..d7d03691 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs @@ -0,0 +1,10 @@ +namespace SJZY.Track.Domain.Dtos.Order; + +public class OrderTransportDto +{ + public int OrderId { get; set; } + + public int ServiceProviderId { get; set; } + + public int SubSystemId { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs index c52c081b..dbe0b308 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs @@ -78,4 +78,9 @@ public class GetTrackPullConfigDetailOutputVO /// 轨迹明细路径 /// public string TrackDetailsPath { get; set; } + + /// + /// 轨迹内容代码 + /// + public string? TrackContentCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs index e01e5a50..6392d05e 100644 --- a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs +++ b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs @@ -68,4 +68,11 @@ public interface IProvideQueries int pageSize = 1000); Task GetTrackContentAsync(int subSystemId, string trackCode); + + /// + /// 查找订单和服务商信息 + /// + /// 订单id + /// 订单和服务商信息 + Task> FindOrderWithServiceProviderAsync(int[] orderIds); } \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs index 5ffffe7a..60043689 100644 --- a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs +++ b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs @@ -122,7 +122,7 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, return await Context.Queryable() .RightJoin((a, b) => a.Id == b.OrderId) .LeftJoin((a, b, c) => b.ServiceProviderId == c.Id) - .Where((a, b) => b.ServiceProviderId == serviceProvider && !a.IsCompleted) + .Where((a, b) => b.ServiceProviderId == serviceProvider && !a.IsCompleted && a.IsTriggerPull==1) .Select((a, b, c) => new OrderWithServiceProviderVO { OrderNo = a.OrderNo, @@ -136,6 +136,20 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, .Take(pageSize) .ToListAsync(); } + + public async Task> FindOrderWithServiceProviderAsync(int[] orderIds) + { + return await Context.Queryable() + .InnerJoin((a, b) => a.Id == b.OrderId) + .Where((a, b) => orderIds.Contains( a.Id) && !a.IsCompleted) + .Select((a, b) => new OrderTransportDto + { + OrderId = a.Id, + ServiceProviderId = b.ServiceProviderId, + SubSystemId = a.SubSystemId + }) + .ToListAsync(); + } public async Task GetTrackContentAsync(int subSystemId, string trackCode) { diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index aa825973..6f2130ae 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -1,5 +1,6 @@ using SJZY.Track.Domain; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Order; namespace SJZY.Track.Repository.Repositories; @@ -21,7 +22,9 @@ public class OrderRepository : BasicRepository, IOrderRepository, I public Task UpdateBatchIdsAsync(List ids, int newValue) { - return Context.Ado.ExecuteCommandAsync("UPDATE `t_order` SET `DeficiencyTag` = @newValue WHERE `Id` IN @ids", new { ids, newValue }); + var idsString = string.Join(",", ids); + return Context.Ado.ExecuteCommandAsync( + $"UPDATE `t_order` SET `DeficiencyTag` = @newValue ,UpdateTime= current_timestamp WHERE `Id` IN ({idsString})", new { newValue }); } public async Task UpdateOrderAsync(OrderEntity order) diff --git a/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs index b3267e8a..41d9053b 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs @@ -72,7 +72,8 @@ public class TrackPullConfigRepository : BasicRepository, { Id = trackPull.Id, SubSystem = system.CnName, - ServiceProvider = service.Name + ServiceProvider = service.Name, + TrackContentCode = paramsConfig.TrackContentCode }, true) .SingleAsync(); } From 3df894d20b45ebd5717b5013be5e5468709fb714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Sat, 27 Jul 2024 09:39:02 +0800 Subject: [PATCH 40/60] =?UTF-8?q?fix:=20=E8=8A=82=E7=82=B9=E8=A1=A8?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AD=90=E7=B3=BB=E7=BB=9F=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrackNodeService.cs | 12 ++++++++ .../ITrackNodeRepository.cs | 7 +++++ .../Dtos/TrackNode/TrackNodeDto.cs | 5 ++++ .../Repositories/TrackNodeRepository.cs | 29 +++++++++++++++++-- 4 files changed, 51 insertions(+), 2 deletions(-) rename src/SJZY.Track.Application/Services/{TrackNodeServices => TrackNode}/TrackNodeService.cs (92%) diff --git a/src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs similarity index 92% rename from src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs rename to src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs index 7b8f3d3a..76506271 100644 --- a/src/SJZY.Track.Application/Services/TrackNodeServices/TrackNodeService.cs +++ b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs @@ -54,6 +54,18 @@ namespace SJZY.Track.Application.Services.TrackNodeServices var resultDto = await _trackNodeRepository.GetPageList(queryParam); return resultDto; } + + /// + /// 获取详情 + /// + /// 节点id + /// + [HttpPost("GetDetail")] + public async Task GetDetail(int nodeid) + { + var resultDto = await _trackNodeRepository.GetDetail(nodeid); + return new UnifyResultDto(true,resultDto); + } /// /// 获取分页轨迹字典,下拉框用的 diff --git a/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs index 10d1cb70..6ab6f473 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs @@ -24,4 +24,11 @@ public interface ITrackNodeRepository:IBasicRepository /// /// Task DeleteById(long inputId); + + /// + /// 获取详情 + /// + /// + /// + Task GetDetail(long id); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs index 185f432f..401ec773 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs @@ -14,6 +14,11 @@ public class TrackNodeDto /// 子系统id /// public int SubSystemId { get; set; } + + /// + /// 系统名称 + /// + public string? SystemName { get; set; } /// /// 节点名称 diff --git a/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs index be340230..9f767780 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs @@ -11,10 +11,11 @@ public class TrackNodeRepository: BasicRepository,ITrackNodeRep var result = await Context.Queryable() .LeftJoin((t,u1)=>t.CreateUserId==u1.Id) .LeftJoin((t,u1,u2)=>t.UpdateUserId==u2.Id) + .LeftJoin((t,u1,u2,u3)=>t.SubSystemId==u3.Id) .Where((t,u1,u2)=>!t.IsDeleted&&!u1.IsDeleted&&!u2.IsDeleted) .WhereIF(!string.IsNullOrEmpty(queryParam.KeyWord), (t,u1,u2)=>t.NodeName!.Contains(queryParam.KeyWord)||t.NodeEnName!.Contains(queryParam.KeyWord)) .WhereIF(queryParam.SystemId.HasValue,(t,u1,u2)=>t.SubSystemId == queryParam.SystemId.Value) - .Select((t, u1, u2) =>new TrackNodeDto() + .Select((t, u1, u2,u3) =>new TrackNodeDto() { Id = t.Id, NodeName = t.NodeName, @@ -24,7 +25,8 @@ public class TrackNodeRepository: BasicRepository,ITrackNodeRep CreateTime = t.CreateTime, UpdateUserId = t.UpdateUserId, UpdateUserName = u2.Name, - CreateUserName = u1.Name + CreateUserName = u1.Name, + SystemName = u3.CnName }).ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize); return result; @@ -50,4 +52,27 @@ public class TrackNodeRepository: BasicRepository,ITrackNodeRep { return Context.Deleteable().Where(val=>val.Id==inputId).ExecuteCommandAsync(); } + + public async Task GetDetail(long id) + { + var result = await Context.Queryable() + .LeftJoin((t, u1) => t.CreateUserId == u1.Id) + .LeftJoin((t, u1, u2) => t.UpdateUserId == u2.Id) + .LeftJoin((t, u1, u2, u3) => t.SubSystemId == u3.Id) + .Where((t, u1, u2) => !t.IsDeleted && !u1.IsDeleted && !u2.IsDeleted) + .Select((t, u1, u2, u3) => new TrackNodeDto() + { + Id = t.Id, + NodeName = t.NodeName, + NodeEnName = t.NodeEnName, + SubSystemId = t.SubSystemId, + UpdateTime = t.UpdateTime, + CreateTime = t.CreateTime, + UpdateUserId = t.UpdateUserId, + UpdateUserName = u2.Name, + CreateUserName = u1.Name, + SystemName = u3.CnName + }).FirstAsync(); + return result; + } } \ No newline at end of file From e3127924723960f2bf23a6bdb5dd7a40346b3862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Sat, 27 Jul 2024 10:11:29 +0800 Subject: [PATCH 41/60] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4dto=E6=98=A0?= =?UTF-8?q?=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/TrackNode/TrackNodeInput.cs | 6 +++--- .../AutoMapper/TrackNodeMapperProfile.cs | 6 +++--- .../Services/TrackNode/TrackNodeService.cs | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs index 8e313589..d487c033 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs @@ -15,15 +15,15 @@ public class EditTrackNodeInput /// /// 系统id /// - public int SystemId { get; set; } + public int? SubSystemId { get; set; } /// /// 节点名称 /// - public string Name { get; set; } + public string? NodeName { get; set; } /// /// 节点英文名称 /// - public string EnName { get; set; } + public string? NodeEnName { get; set; } } diff --git a/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs index af8699e0..b2226591 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs @@ -12,9 +12,9 @@ public class TrackNodeMapperProfile :Profile { CreateMap(); CreateMap(MemberList.None) - .ForMember(val => val.NodeName, opt => opt.MapFrom(src => src.Name)) - .ForMember(val => val.NodeEnName, opt => opt.MapFrom(src => src.EnName)) - .ForMember(val => val.SubSystemId, opt => opt.MapFrom(src => src.SystemId)); + .ForMember(val => val.NodeName, opt => opt.MapFrom(src => src.NodeName)) + .ForMember(val => val.NodeEnName, opt => opt.MapFrom(src => src.NodeEnName)) + .ForMember(val => val.SubSystemId, opt => opt.MapFrom(src => src.SubSystemId)); } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs index 76506271..c69ed6fd 100644 --- a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs +++ b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs @@ -86,15 +86,15 @@ namespace SJZY.Track.Application.Services.TrackNodeServices { #region 业务校验 var trackNodesEntitys = await _trackNodeRepository.GetListAsync(a => - a.SubSystemId == input.SystemId && (a.NodeName == input.Name || a.NodeEnName == input.EnName)); + a.SubSystemId == input.SubSystemId && (a.NodeName == input.NodeName || a.NodeEnName == input.NodeEnName)); if (trackNodesEntitys.Any()) { - var trackNodeName = trackNodesEntitys.FirstOrDefault(a => a.NodeName == input.Name); + var trackNodeName = trackNodesEntitys.FirstOrDefault(a => a.NodeName == input.NodeName); if (trackNodeName != null) { throw new BusinessException(message: "该子系统下节点名称已存在"); } - var trackNodeEnName = trackNodesEntitys.FirstOrDefault(a => a.NodeEnName == input.EnName); + var trackNodeEnName = trackNodesEntitys.FirstOrDefault(a => a.NodeEnName == input.NodeEnName); if (trackNodeEnName != null) { throw new BusinessException(message: "该子系统下节点英文名称已存在"); @@ -120,8 +120,8 @@ namespace SJZY.Track.Application.Services.TrackNodeServices #endregion - trackNodesEntitys.NodeEnName = input.EnName; - trackNodesEntitys.NodeName = input.Name; + trackNodesEntitys.NodeEnName = input.NodeEnName; + trackNodesEntitys.NodeName = input.NodeName; var isTrue = await _trackNodeRepository.UpdateAsync(trackNodesEntitys); return new UnifyResultDto("200", "修改成功", isTrue); @@ -129,7 +129,7 @@ namespace SJZY.Track.Application.Services.TrackNodeServices private async Task DeleteAsync(EditTrackNodeInput input) { - var trackStatus = await _trackStatusRepository.GetFirstAsync(val => val.Node == input.Id && val.SubSystemId == input.SystemId); + var trackStatus = await _trackStatusRepository.GetFirstAsync(val => val.Node == input.Id && val.SubSystemId == input.SubSystemId); if(trackStatus!=null) { return new UnifyResultDto("200", "删除失败,该节点已被使用", false); From 64acaffb5bbd1ea03a24759fd7daf733dcba87b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Sat, 27 Jul 2024 11:18:44 +0800 Subject: [PATCH 42/60] fix: add a validation --- .../Services/TrackNode/TrackNodeService.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs index c69ed6fd..851d3055 100644 --- a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs +++ b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs @@ -85,6 +85,11 @@ namespace SJZY.Track.Application.Services.TrackNodeServices private async Task AddAsync(EditTrackNodeInput input) { #region 业务校验 + if(string.IsNullOrEmpty(input.NodeName)|| string.IsNullOrEmpty(input.NodeEnName) || !input.SubSystemId.HasValue) + { + return new UnifyResultDto("200", "NodeName,NodeEnName,SubSystemId 必填", false); + } + var trackNodesEntitys = await _trackNodeRepository.GetListAsync(a => a.SubSystemId == input.SubSystemId && (a.NodeName == input.NodeName || a.NodeEnName == input.NodeEnName)); if (trackNodesEntitys.Any()) @@ -111,7 +116,11 @@ namespace SJZY.Track.Application.Services.TrackNodeServices private async Task UpdateAsync(EditTrackNodeInput input) { #region 业务校验 - + if(string.IsNullOrEmpty(input.NodeName)|| string.IsNullOrEmpty(input.NodeEnName) ) + { + return new UnifyResultDto("200", "NodeName,NodeEnName 必填", false); + } + var trackNodesEntitys = await _trackNodeRepository.GetFirstAsync(a => a.Id == input.Id); if (trackNodesEntitys == null) { @@ -129,6 +138,11 @@ namespace SJZY.Track.Application.Services.TrackNodeServices private async Task DeleteAsync(EditTrackNodeInput input) { + if(input.Id <=0 || !input.SubSystemId.HasValue) + { + return new UnifyResultDto("200", "SubSystemId 必填", false); + } + var trackStatus = await _trackStatusRepository.GetFirstAsync(val => val.Node == input.Id && val.SubSystemId == input.SubSystemId); if(trackStatus!=null) { From 7454827e0fa6ad72c7508437d862a095fb783beb Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Sat, 27 Jul 2024 17:44:23 +0800 Subject: [PATCH 43/60] =?UTF-8?q?connect:=20=E5=AF=B9=E6=8E=A5=E9=A2=84?= =?UTF-8?q?=E8=AD=A6=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Common/IdWithNameDto.cs | 8 ++++ .../Helpers/ForewarningHelper.cs | 10 +++-- .../ForewarningServices/ForewarningService.cs | 40 +++++++++++++------ .../Dtos/Forewarning/WarningNitifyDto.cs | 10 +++++ 4 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Common/IdWithNameDto.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/Common/IdWithNameDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Common/IdWithNameDto.cs new file mode 100644 index 00000000..7027b635 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Common/IdWithNameDto.cs @@ -0,0 +1,8 @@ +namespace SJZY.Track.Application.Contract.Dtos.Common; + +public class IdWithNameDto +{ + public int Id { get; set; } + + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index 6b572c44..eb79d6f0 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -2,6 +2,7 @@ using System.Dynamic; using Nest; using Newtonsoft.Json.Linq; using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.Common; using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Dtos.Forewarning; @@ -119,7 +120,7 @@ public class ForewarningHelper case RuleFactorType.LeavePort: if (value.Type is not JTokenType.String) { - throw new BusinessException(message: "货物类型只接收字符串"); + throw new BusinessException(message: "起运港只接收字符串"); } rules[row].LeavePort = strValue; @@ -127,7 +128,7 @@ public class ForewarningHelper case RuleFactorType.ProductCode: if (value.Type is not JTokenType.String) { - throw new BusinessException(message: "货物类型只接收字符串"); + throw new BusinessException(message: "产品代码只接收字符串"); } rules[row].ProductCode = strValue; @@ -161,8 +162,9 @@ public class ForewarningHelper }).ToList(); } - public static EditWarningOutput MapWarningSummary(WarningEntity warning) + public static EditWarningOutput MapWarningSummary(WarningEntity warning, List statusList) { + var statusDic = statusList.ToDictionary(x => x.Id, x => x.Name); return new EditWarningOutput { Name = warning.Name, @@ -174,7 +176,9 @@ public class ForewarningHelper { Id = x.Id, StartTrackStatusId = x.StartTrackStatusId, + StartTrackStatus = statusDic.TryGetValue(x.StartTrackStatusId, out var start) ? start : "", EndTrackStatusId = x.EndTrackStatusId, + EndTrackStatus = statusDic.TryGetValue(x.EndTrackStatusId, out var end) ? end : "", NotifyUserId = x.NotifyUserId, }).ToList(), WarningFactors = warning.WarningFactors.Select(x => new WarningFactorWithIdDto diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index abe4f846..a155a5f6 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -1,8 +1,11 @@ using System.ComponentModel.DataAnnotations; +using SJZY.Track.Application.Contract.Dtos.Common; using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Dtos.TrackStatus; using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -17,7 +20,7 @@ public class ForewarningService : ApplicationService { _warningRepository = warningRepository; } - + /// /// 获取预警分页列表 /// @@ -29,7 +32,7 @@ public class ForewarningService : ApplicationService if (!inputVo.KeyWord.IsNullOrEmpty()) inputVo.KeyWord = inputVo.KeyWord!.Trim(); return await _warningRepository.GetWarningPageListAsync(inputVo); } - + /// /// 创建预警 /// @@ -45,21 +48,23 @@ public class ForewarningService : ApplicationService { throw new BusinessException(message: "该子系统下的客户已经存在一个同名预警: " + warning.Name); } - + warning.WarningRules = ForewarningHelper.CalcRuleList(input.TrackStatusSpans, input.WarningFactors); warning.WarningFactors = ForewarningHelper.MapFactorEntities(input.WarningFactors); warning.WarningNotifies = ForewarningHelper.MapNotifyEntities(input); await _warningRepository.CreateForewarningAsync(warning); return true; } - + /// /// 编辑预警 /// /// + /// /// [HttpPost("EditWarning")] - public async Task EditWarning(int warningId) + public async Task EditWarning(int warningId, + [FromServices] IBasicQuery statusQuery) { var warning = await _warningRepository.GetByIdAsync(warningId); @@ -67,8 +72,15 @@ public class ForewarningService : ApplicationService { throw new BusinessException(message: "预警不存在"); } - - return ForewarningHelper.MapWarningSummary(warning); + + var statusList = await statusQuery.GetListAsync(x => x.SubSystemId == warning.SubSystemId, x => + new IdWithNameDto + { + Id = x.Id, + Name = x.Status + }); + + return ForewarningHelper.MapWarningSummary(warning, statusList); } /// @@ -86,7 +98,8 @@ public class ForewarningService : ApplicationService } if (await _warningRepository.IsAnyAsync(x => - x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.Id != warning.Id)) + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.Id != warning.Id && + x.Name == input.Name)) { throw new BusinessException(message: "该子系统下的客户已经存在一个同名预警: " + warning.Name); } @@ -120,7 +133,7 @@ public class ForewarningService : ApplicationService { throw new BusinessException(message: "预警不存在"); } - + if (isEnable) { if (await _warningRepository.IsAnyAsync(x => @@ -129,7 +142,7 @@ public class ForewarningService : ApplicationService throw new BusinessException(message: "该子系统下的客户已经存在一个启用的预警,请先禁用"); } } - + warning.SetEnable(isEnable); return await _warningRepository.TurnWarningAsync(warning); @@ -142,15 +155,16 @@ public class ForewarningService : ApplicationService /// /// [HttpGet("GetWarningRuleList")] - public async Task> GetWarningRuleListAsync([Required] int warningId, [FromServices] IBasicQuery factorQuery) + public async Task> GetWarningRuleListAsync([Required] int warningId, + [FromServices] IBasicQuery factorQuery) { var factors = await factorQuery.GetListAsync(x => x.WarningId == warningId, x => x.Type); var rules = await _warningRepository.GetWarningRuleListAsync(warningId); - + var dynamicList = ForewarningHelper.DynamicCalcRuleList(rules, factors); return dynamicList; } - + /// /// 修改预警规则时效 /// diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs index 255a421a..f831cfeb 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningNitifyDto.cs @@ -12,6 +12,16 @@ public class WarningNitifyDto /// public int EndTrackStatusId { get; set; } + /// + /// 起始轨迹状态 + /// + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态 + /// + public string EndTrackStatus { get; set; } = null!; + /// /// 通知人id /// From 769ba9e07b8ccda23d850279c7f6f47e73aaf611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Mon, 29 Jul 2024 10:31:57 +0800 Subject: [PATCH 44/60] =?UTF-8?q?Merge=20remote-tracking=20branch=20'origi?= =?UTF-8?q?n/S04=E8=BD=A8=E8=BF=B9=E9=A2=84=E8=AD=A6'=20into=20S04?= =?UTF-8?q?=E8=BD=A8=E8=BF=B9=E9=A2=84=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs feat: 调整轨迹区域添加了国家名称字段 --- .../AutoMapper/ForewarningMapperProfile.cs | 7 ++-- .../KPIAreaAggregate/RuleAreaInfoEntity.cs | 12 +++++-- .../Forewarning/AddRuleAreaInfoRequest.cs | 10 ++++-- .../Dtos/Forewarning/AreaDto.cs | 20 ++++++++++++ .../Dtos/Forewarning/AreaInfoDto.cs | 9 ++++-- .../Forewarning/UpdateRuleAreaInfoRequest.cs | 8 ++++- .../Repositories/KpiAreaRepository.cs | 32 ++++++++----------- .../Repositories/TrackNodeRepository.cs | 2 +- 8 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs index 2498dccb..6a48362a 100644 --- a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs @@ -14,10 +14,10 @@ public class ForewarningMapperProfile :Profile CreateMap(MemberList.None) .Ignore(x => x.WarningFactors); CreateMap(MemberList.None); - CreateMap(); CreateMap(MemberList.None); CreateMap(MemberList.None) - .ForMember(dest => dest.Country, opt => opt.MapFrom(src => src.Country)) + .ForMember(dest => dest.CountryCode, opt => opt.MapFrom(src => src.CountryCode)) + .ForMember(dest => dest.CountryName, opt => opt.MapFrom(src => src.CountryName)) .ForMember(dest => dest.Province, opt => opt.MapFrom(src => src.Province)) .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) @@ -29,7 +29,8 @@ public class ForewarningMapperProfile :Profile .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)); CreateMap(MemberList.None) - .ForMember(dest => dest.Country, opt => opt.MapFrom(src => src.Country)) + .ForMember(dest => dest.CountryCode, opt => opt.MapFrom(src => src.CountryCode)) + .ForMember(dest => dest.CountryName, opt => opt.MapFrom(src => src.CountryName)) .ForMember(dest => dest.Province, opt => opt.MapFrom(src => src.Province)) .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs index 5a1b97c7..b1afa3c6 100644 --- a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs @@ -16,10 +16,16 @@ public class RuleAreaInfoEntity : IEntity public int AreaId { get; set; } /// - /// 国家或地区 + /// 国家或地区二字码 /// - [SugarColumn(ColumnName = "Country", Length = 128, ColumnDescription = "国家或地区")] - public string Country { get; set; } + [SugarColumn(ColumnName = "CountryCode", Length = 128, ColumnDescription = "国家或地区二字码")] + public string CountryCode { get; set; } + + /// + /// 国家或地区名称 + /// + [SugarColumn(ColumnName = "CountryName", Length = 128, ColumnDescription = "国家或地区名称")] + public string CountryName { get; set; } /// /// 州或者省份 diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs index 08616063..2ce1878c 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs @@ -5,10 +5,16 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public class AddRuleAreaInfoRequest { /// - /// 国家名称,必填项。 + /// 国家二字码,必填项。 /// [Required] - public string Country { get; set; } + public string CountryCode { get; set; } + + /// + /// 国家名称 + /// + [Required] + public string CountryName { get; set; } /// /// 省份名称,可为空。 diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs index d0703d4a..2ed7cc9f 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs @@ -2,8 +2,28 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public class AreaDto { + /// + /// 区域id + /// public int Id { get; set; } + + /// + /// 子系统id + /// public int SubSystemId { get; set; } + + /// + /// 系统名称 + /// + public string SystemName { get; set; } + + /// + /// 区域名称 + /// public string Name { get; set; } + + /// + /// 更新时间 + /// public DateTime UpdateTime { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs index 9ac65e86..75e24e5e 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs @@ -13,9 +13,14 @@ public class RuleAreaInfoDto public int AreaId { get; set; } /// - /// 国家或地区 + /// 国家或地区 二字码 /// - public string Country { get; set; } + public string CountryCode { get; set; } + + /// + /// 国家名称 + /// + public string CountryName { get; set; } /// /// 省份 diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs index 29a25f7f..8b1d4978 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs @@ -12,11 +12,17 @@ public class UpdateRuleAreaInfoRequest /// public int Id { get; set; } + /// + /// 国家二字码,必填项。 + /// + [Required] + public string CountryCode { get; set; } + /// /// 国家名称,必填项。 /// [Required] - public string Country { get; set; } + public string CountryName { get; set; } /// /// 省份名称,可为空。 diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs index 9717997a..c1a7d22a 100644 --- a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -1,6 +1,7 @@ using SJZY.Track.Domain; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.VEntities; namespace SJZY.Track.Repository.Repositories; @@ -41,24 +42,18 @@ public class KpiAreaRepository : BasicRepository, IKpiAreaReposi /// public async Task> GetAreas(QueryAreaRequest query) { - var queryable = Context.Queryable(); - if (!string.IsNullOrEmpty(query.Name)) - { - queryable = queryable.Where(x => x.Name.Contains(query.Name)); - } - - if (query.SystemId.HasValue) - { - queryable = queryable.Where(x => x.SubSystemId == query.SystemId.Value); - } - - return await queryable.OrderBy(x => x.Id, OrderByType.Desc) - .Select(val => new AreaDto() + return await Context.Queryable() + .InnerJoin((area,sys)=>area.SubSystemId==sys.Id) + .WhereIF(!string.IsNullOrEmpty(query.Name),(area,sys)=>area.Name.Contains(query.Name)) + .WhereIF(query.SystemId.HasValue,(area,sys)=>area.SubSystemId == query.SystemId.Value) + .OrderBy((area,sys) => area.UpdateTime, OrderByType.Desc) + .Select((area,sys) => new AreaDto() { - Id = val.Id, - Name = val.Name, - SubSystemId = val.SubSystemId, - UpdateTime = val.CreateTime + Id = area.Id, + Name = area.Name, + SystemName = sys.CnName, + SubSystemId = area.SubSystemId, + UpdateTime = area.CreateTime }) .ToPagedListAsync(query.PageIndex, query.PageSize); } @@ -78,7 +73,8 @@ public class KpiAreaRepository : BasicRepository, IKpiAreaReposi Id = val.Id, AreaId = val.AreaId, City = val.City, - Country = val.Country, + CountryCode = val.CountryCode, + CountryName = val.CountryName, LeftPostcode = val.LeftPostcode, RightPostcode = val.RightPostcode, Province = val.Province diff --git a/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs index 9f767780..cd6d8003 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs @@ -59,7 +59,7 @@ public class TrackNodeRepository: BasicRepository,ITrackNodeRep .LeftJoin((t, u1) => t.CreateUserId == u1.Id) .LeftJoin((t, u1, u2) => t.UpdateUserId == u2.Id) .LeftJoin((t, u1, u2, u3) => t.SubSystemId == u3.Id) - .Where((t, u1, u2) => !t.IsDeleted && !u1.IsDeleted && !u2.IsDeleted) + .Where((t, u1, u2) => !t.IsDeleted && !u1.IsDeleted && !u2.IsDeleted&& t.Id==id) .Select((t, u1, u2, u3) => new TrackNodeDto() { Id = t.Id, From 6b211d8f7ff39ae51f464699209d4dc3b87e6372 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Mon, 29 Jul 2024 11:55:36 +0800 Subject: [PATCH 45/60] temp --- .../Dtos/Forewarning/AreaCacheEntry.cs | 29 +++++ .../Forewarning/ForewarningRuleCacheEntry.cs | 69 ++++++++++ .../Services/IForewarningCacheService.cs | 8 ++ .../Services/IForewarningNotifyService.cs | 4 +- .../Services/IRuleFactorCacheService.cs | 32 ----- ...TrackChangeAfterUpdateOrderEventHandler.cs | 90 ++++++------- .../ForewarningCacheService.cs | 13 ++ .../ForewarningNotifyService.cs | 121 +----------------- ...arningOrderModel.cs => WarningOrderDto.cs} | 24 +++- 9 files changed, 187 insertions(+), 203 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs create mode 100644 src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs delete mode 100644 src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs create mode 100644 src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs rename src/SJZY.Track.Domain/Dtos/Forewarning/{ForewarningOrderModel.cs => WarningOrderDto.cs} (56%) diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs new file mode 100644 index 00000000..1e87ff17 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class AreaCacheEntry +{ + /// + /// 国家或地区 + /// + public string Country { get; set; } = null!; + + /// + /// 省份 + /// + public string? Province { get; set; } + + /// + /// 城市 + /// + public string? City { get; set; } + + /// + /// 开始邮编 + /// + public string? LeftPostcode { get; set; } + + /// + /// 截止邮编 + /// + public string? RightPostcode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs new file mode 100644 index 00000000..09ab3e1d --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs @@ -0,0 +1,69 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class ForewarningRuleCacheEntry +{ + /// + /// 自增主键 + /// + public int Id { get; set; } + + /// + /// 预警id + /// + public int WarningId { get; set; } + + /// + /// 时效(小时) e.g. 24 + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) e.g. 9 10 11.. + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 e.g. 3 2 1 + /// + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态id + /// + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + public int EndTrackStatusId { get; set; } + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 月份 + /// + public List? Months { get; set; } + + /// + /// 区域 + /// + public List? AreaId { get; set; } + + /// + /// 是否中转 + /// + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + public string? LeavePort { get; set; } + + /// + /// 产品编码 + /// + public string? ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs new file mode 100644 index 00000000..ce6550f1 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs @@ -0,0 +1,8 @@ +using SJZY.Track.Application.Contract.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Services; + +public interface IForewarningCacheService +{ + Task> GetRulesAsync(int subSystemId); +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs index 58dcd995..8830f610 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs @@ -13,14 +13,14 @@ public interface IForewarningNotifyService /// /// 预警订单模型。 /// 创建操作的结果,以整数形式返回。 - Task WarningCalculateAsync(List order); + Task WarningCalculateAsync(List order); /// /// 删除预警通知。 /// /// 预警订单模型。 /// 删除操作的结果,以整数形式返回。 - Task DeleteForewarningNotify(ForewarningOrderModel order); + Task DeleteForewarningNotify(WarningOrderDto order); /// /// 发送通知。 diff --git a/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs deleted file mode 100644 index fb1f742b..00000000 --- a/src/SJZY.Track.Application.Contract/Services/IRuleFactorCacheService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; -using SJZY.Track.Domain.Dtos.Forewarning; - -namespace SJZY.Track.Application.Contract.Services; - -/// -/// 定义了与规则因子缓存相关的服务接口。 -/// -public interface IRuleFactorCacheService -{ - /// - /// 获取所有因子收集的规则。 - /// - /// 规则数组。 - Task GetAllFactorCollect(); - - /// - /// 获取所有规则因子。 - /// - /// 规则因子实体列表。 - Task> GetAllRuleFactor(); - - /// - /// 清除因子缓存。 - /// - void ClearFactorCache(); - - /// - /// 清除规则缓存。 - /// - void ClearRuleCache(); -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index f5766880..0b657f6c 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -67,67 +67,59 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }); // 预警计算 - var warningOrders = orders.Select(order => new ForewarningOrderModel - { - Id = order.Id, - TrackStatusId = @event.TrackStatusId, - SubSystemId = order.SubSystemId, - CustomerId = order.CustomId, - CargoType = order.CargoType, - Month = order.CreateTime.Month, - Area = DetermineAreaBasedOnOrderDetails(order), - IsTransit = order.IsTransit, - LeavePort = order.LeavePort, - ProductCode = order.ProductCode - }).ToList(); + var warningOrders = orders.Select(order => MapWarningOrderDto(order, @event.TrackStatusId)).ToList(); + _forewarningNotifyService.WarningCalculateAsync(warningOrders); } - private OrderEntity MapOrderSummary(OrderEntity x) + private OrderEntity MapOrderSummary(OrderEntity order) { return new OrderEntity { - Id = x.Id, - SubSystemId = x.SubSystemId, - CustomId = x.CustomId, + Id = order.Id, + SubSystemId = order.SubSystemId, + CustomId = order.CustomId, // 轨迹 - IsCompleted = x.IsCompleted, - LatestTrackContent = x.LatestTrackContent, - LatestTrackEnContent = x.LatestTrackEnContent, - LatestTrackPlace = x.LatestTrackPlace, - LatestTrackTime = x.LatestTrackTime, - LatestTrackTimeZone = x.LatestTrackTimeZone, + IsCompleted = order.IsCompleted, + LatestTrackContent = order.LatestTrackContent, + LatestTrackEnContent = order.LatestTrackEnContent, + LatestTrackPlace = order.LatestTrackPlace, + LatestTrackTime = order.LatestTrackTime, + LatestTrackTimeZone = order.LatestTrackTimeZone, // 因素 - CargoType = x.CargoType, - CreateTime = x.CreateTime, - ArrivalCountry = x.ArrivalCountry, - ArrivalProvince = x.ArrivalProvince, - ArrivalCity = x.ArrivalCity, - ArrivalPostCode = x.ArrivalPostCode, - IsTransit = x.IsTransit, - LeavePort = x.LeavePort, - ProductCode = x.ProductCode + CargoType = order.CargoType, + CreateTime = order.CreateTime, + ArrivalCountry = order.ArrivalCountry, + ArrivalProvince = order.ArrivalProvince, + ArrivalCity = order.ArrivalCity, + ArrivalPostCode = order.ArrivalPostCode, + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode }; } - -// Placeholder methods for deriving or converting values. You'll need to implement these based on your specific logic. - private int DetermineTrackBasedOnOrderDetails(OrderEntity order) + + private WarningOrderDto MapWarningOrderDto(OrderEntity order, int trackStatusId) { - // Implement logic to determine Track - return default; - } - - private int? DetermineMonthBasedOnOrderDetails(OrderEntity order) - { - // Implement logic to determine Month - return default; - } - - private int? DetermineAreaBasedOnOrderDetails(OrderEntity order) - { - // Implement logic to determine Area - return default; + return new WarningOrderDto + { + Id = order.Id, + TrackStatusId = trackStatusId, + SubSystemId = order.SubSystemId, + CustomerId = order.CustomId, + + CargoType = order.CargoType, + Month = order.CreateTime.Month, + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode, + + ArrivalCountry = order.ArrivalCountry, + ArrivalProvince = order.ArrivalProvince, + ArrivalCity = order.ArrivalCity, + ArrivalPostCode = order.ArrivalPostCode, + }; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs new file mode 100644 index 00000000..289f3bbf --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -0,0 +1,13 @@ +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Services; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +public class ForewarningCacheService: IForewarningCacheService, ISingletonDependency +{ + public Task> GetRulesAsync(int subSystemId) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index c097ff7c..f4b2c418 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -14,15 +14,13 @@ namespace SJZY.Track.Application.Services.ForewarningServices; /// public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency { - private IRuleFactorCacheService _ruleFactorCache; IReadOnlyDictionary> _ruleGroupDict; IReadOnlyDictionary> _factorDict; private IReadOnlyDictionary _rules; readonly INotifyService _notifyService; - public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService) + public ForewarningNotifyService(INotifyService notifyService) { - _ruleFactorCache = ruleFactorCache; _notifyService = notifyService; } @@ -31,31 +29,14 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep /// /// 创建预警通知需要的订单信息 /// 创建的通知总量,0表示没有规则 - public async Task WarningCalculateAsync(List order) + public async Task WarningCalculateAsync(List order) { throw new NotImplementedException(); } - /// - /// 清除预警通知 - /// - /// 订单信息 - /// 清理的行数 - public async Task DeleteForewarningNotify(ForewarningOrderModel order) + public Task DeleteForewarningNotify(WarningOrderDto order) { - var rules = GetRule(order); - if (rules == null || rules.Count == 0) - return 0; - - var willDeleteMembers = new List(); - foreach (var rule in rules) - { - var allRuleNotities = DeleteNotifyValue(rule, order.Id); - willDeleteMembers.AddRange(allRuleNotities); - } - - await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKeyPrefix, willDeleteMembers.ToArray()); - return willDeleteMembers.Count; + throw new NotImplementedException(); } public void SendNotification(int intervalMinute) @@ -96,33 +77,6 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep return members; } - /// - /// 获取规则 - /// - /// - /// - private List GetRule(ForewarningOrderModel order) - { - if (!_factorDict.TryGetValue(GetFactorKey(order.CustomerId, order.SubSystemId), out var factors)) - { - return null; - } - - var keys = GetForewarningKeys(factors, order); - var result = new List(); - - foreach (var item in keys) - { - if (!_ruleGroupDict.TryGetValue(item, out var rules)) - continue; - - var allRules = rules.Where(val => val.TrackStart <= order.TrackStatusId && val.TrackEnd >= order.TrackStatusId); - result.AddRange(allRules); - } - - return result; - } - private async ValueTask ExecuteRule(List rules, int orderId) { var members = new List(); @@ -162,71 +116,4 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep var result = new RuleNotifyValue(ruleItem.Id, orderId, sort, ruleItem.TrackEnd); return result.ToString(); } - - private List GetForewarningKeys(List factors, IForewarningFactorValue rule) - { - var keys = new List(); - foreach (var factor in factors) - { - var key = GetRuleKey(rule, factor); - keys.Add(key); - } - - return keys; - } - - private async Task Init() - { - // todo:缓存设计有问题 重构 120s 10w 30w 3000k/s - var allFactorCollect = await _ruleFactorCache.GetAllFactorCollect(); - var factors = await _ruleFactorCache.GetAllRuleFactor(); - var factorsMap = factors.GroupBy(val => val.RuleId) - .ToDictionary(val => val.Key, val => val.First()); - - _rules = allFactorCollect.ToDictionary(val => val.Id); - - _factorDict = factors.GroupBy(val => GetFactorKey(val.CustomerId, val.SystemId)) - .ToDictionary(val => val.Key, val => val.ToList()); - - _ruleGroupDict = allFactorCollect.GroupBy(x => GetRuleKey(x, factorsMap[x.RuleId])) - .ToDictionary(val => val.Key, val => val.ToList()); - } - - private string GetFactorKey(int customerId, int systemId) - { - return $"{customerId}:{systemId}"; - } - - private string GetRuleKey(IForewarningFactorValue rule, RuleFactor factors) - { - var key = ""; - foreach (var factorItem in factors.FactorItems) - { - key += GetFactorValue(factorItem, rule); - } - - return key; - } - - private string GetFactorValue(FactorItemModel factorItem, IForewarningFactorValue rule) - { - switch (factorItem.FactorType) - { - case RuleFactorType.Areas: - return rule.Area.HasValue ? rule.Area.Value.ToString() : throw new Exception("区域不能为空"); - case RuleFactorType.CargoType: - return rule.CargoType; - case RuleFactorType.LeavePort: - return rule.LeavePort; - case RuleFactorType.Months: - return rule.Month.HasValue ? rule.Month.Value.ToString() : throw new Exception("月份不能为空"); - case RuleFactorType.ProductCode: - return rule.ProductCode; - case RuleFactorType.IsTransit: - return rule.IsTransit.HasValue ? "1" : "0"; - // Add additional cases for other RuleFactorTypes as needed - default: - throw new Exception("未知的规则类型"); - } - } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningOrderDto.cs similarity index 56% rename from src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs rename to src/SJZY.Track.Domain/Dtos/Forewarning/WarningOrderDto.cs index 3767abcb..4cdc5a91 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningOrderModel.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningOrderDto.cs @@ -1,6 +1,6 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; -public class ForewarningOrderModel:IForewarningFactorValue +public class WarningOrderDto { /// /// 订单id @@ -20,8 +20,6 @@ public class ForewarningOrderModel:IForewarningFactorValue public int? Month { get; set; } - public int? Area { get; set; } - public bool? IsTransit { get; set; } /// @@ -30,4 +28,24 @@ public class ForewarningOrderModel:IForewarningFactorValue public string? LeavePort { get; set; } public string? ProductCode { get; set; } + + /// + /// 目的城市 + /// + public string ArrivalCity { get; set; } = null!; + + /// + /// 目的国家 + /// + public string ArrivalCountry { get; set; } = null!; + + /// + /// 到达邮编 + /// + public string? ArrivalPostCode { get; set; } + + /// + /// 到达州省 + /// + public string? ArrivalProvince { get; set; } } \ No newline at end of file From d0c2a92a8214115d02ceb9e93a51ef957b05bad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Mon, 29 Jul 2024 14:09:15 +0800 Subject: [PATCH 46/60] =?UTF-8?q?feat:=20=E5=8C=BA=E5=9F=9F=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BA=86=E8=BF=94=E5=9B=9E=E5=9B=BD=E5=AE=B6id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EventHandlers/TrackPushEventHandler.cs | 1 - .../Services/TrackNode/TrackNodeService.cs | 4 +- .../Dtos/Forewarning/AreaInfoDto.cs | 5 + .../VEntities/VCountryEntity.cs | 110 ++++++++++++++++++ .../Repositories/KpiAreaRepository.cs | 29 ++--- 5 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 src/SJZY.Track.Domain/VEntities/VCountryEntity.cs diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs index ed6b7522..369221c7 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs @@ -113,7 +113,6 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe var tracks = await _trackDetailsRepository.GetListAsync(@event.OrderIds, @event.TrackCode); tracks = tracks.DistinctBy(x => x.OrderId).ToList(); // 防止重复推送 - var temp=this.DateTimeFormat(DateTime.Now, -8.0, config); if (tracks.Count == 0) return; // 一个能推的轨迹都不存在 // tips:人工推送只要能推就推了,不会校验已推和顺序问题,因为可能是更新 diff --git a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs index 851d3055..c9bd2637 100644 --- a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs +++ b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs @@ -1,13 +1,11 @@ -using Microsoft.Extensions.Localization; using SJZY.Track.Application.Contract.Dtos.TrackNode; using SJZY.Track.Application.Contract.Dtos.TrackStatus; -using SJZY.Track.Application.Localization; using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.TrackNode; using Volo.Abp.DependencyInjection; -namespace SJZY.Track.Application.Services.TrackNodeServices +namespace SJZY.Track.Application.Services.TrackNode { /// /// 轨迹节点服务 diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs index 75e24e5e..d78454b6 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs @@ -22,6 +22,11 @@ public class RuleAreaInfoDto /// public string CountryName { get; set; } + /// + /// 国家id + /// + public int CountryId { get; set; } + /// /// 省份 /// diff --git a/src/SJZY.Track.Domain/VEntities/VCountryEntity.cs b/src/SJZY.Track.Domain/VEntities/VCountryEntity.cs new file mode 100644 index 00000000..46310904 --- /dev/null +++ b/src/SJZY.Track.Domain/VEntities/VCountryEntity.cs @@ -0,0 +1,110 @@ +using SqlSugar; +using System; + +namespace SJZY.Track.Domain.VEntities; + +[SugarTable("v_country")] +public class VCountryEntity : IFullAuditedBasicEntitys +{ + /// + /// 主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 区域id + /// + [SugarColumn(ColumnName = "AreaId")] + public int AreaId { get; set; } + + /// + /// 币种id + /// + [SugarColumn(ColumnName = "CurrencyId", IsNullable = true)] + public int? CurrencyId { get; set; } + + /// + /// 中文名 + /// + [SugarColumn(ColumnName = "CnName")] + public string CnName { get; set; } + + /// + /// 英文名 + /// + [SugarColumn(ColumnName = "EnName")] + public string EnName { get; set; } + + /// + /// 二字代码 + /// + [SugarColumn(ColumnName = "Digit2Code")] + public string Digit2Code { get; set; } + + /// + /// 三字代码 + /// + [SugarColumn(ColumnName = "Digit3Code", IsNullable = true)] + public string Digit3Code { get; set; } + + /// + /// 企业代码类型 + /// + [SugarColumn(ColumnName = "EnterpriseCodeType", IsNullable = true)] + public string EnterpriseCodeType { get; set; } + + /// + /// 区号 + /// + [SugarColumn(ColumnName = "CountryCode", IsNullable = true)] + public int? CountryCode { get; set; } + + /// + /// 时差 + /// + [SugarColumn(ColumnName = "JetLag")] + public int JetLag { get; set; } + + /// + /// 城市名 + /// + [SugarColumn(ColumnName = "CountryName", IsNullable = true)] + public string CountryName { get; set; } + + /// + /// 是否不可使用 + /// + [SugarColumn(ColumnName = "IsUnusable", IsNullable = false)] + public bool IsUnusable { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", IsNullable = true)] + public int? CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", IsNullable = false, DefaultValue = "CURRENT_TIMESTAMP")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", IsNullable = true)] + public int? UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", IsNullable = true)] + public DateTime? UpdateTime { get; set; } + + /// + /// 是否删除 + /// + [SugarColumn(ColumnName = "IsDeleted", IsNullable = false)] + public bool IsDeleted { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs index c1a7d22a..f6226432 100644 --- a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -65,26 +65,29 @@ public class KpiAreaRepository : BasicRepository, IKpiAreaReposi /// public async Task> GetAreaInfos(QueryAreaInfoRequest query) { - var queryable = Context.Queryable(); - queryable = queryable.Where(x => x.AreaId == query.AreaId); - return await queryable.OrderBy(x => x.Id, OrderByType.Desc) - .Select(val => new RuleAreaInfoDto() + return await Context.Queryable() + .InnerJoin((x,c)=>x.CountryCode==c.Digit2Code) + .Where(x => x.AreaId == query.AreaId) + .OrderBy(x => x.UpdateTime, OrderByType.Desc) + .Select((x,c)=> new RuleAreaInfoDto() { - Id = val.Id, - AreaId = val.AreaId, - City = val.City, - CountryCode = val.CountryCode, - CountryName = val.CountryName, - LeftPostcode = val.LeftPostcode, - RightPostcode = val.RightPostcode, - Province = val.Province + Id = x.Id, + AreaId = x.AreaId, + City = x.City, + CountryId = c.Id, + CountryCode = x.CountryCode, + CountryName = x.CountryName, + LeftPostcode = x.LeftPostcode, + RightPostcode = x.RightPostcode, + Province = x.Province }) .ToPagedListAsync(query.PageIndex, query.PageSize); } public Task GetAreaInfoById(int id) { - return Context.Queryable().FirstAsync(val => val.Id == id)!; + return Context.Queryable() + .FirstAsync(val => val.Id == id)!; } /// From 73422ba703f6fb66360b7aa68a53963fe1ee3cfe Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Mon, 29 Jul 2024 15:03:37 +0800 Subject: [PATCH 47/60] review --- .../Events/OrderIdentifier.cs | 4 -- .../TrackChangeAfterUpdateOrderEvent.cs | 10 +++++ .../Events/TrackUpsertEvent.cs | 7 +++- .../Services/IForewarningCacheService.cs | 16 +++++++- .../Services/INotifyService.cs | 6 --- ...TrackChangeAfterUpdateOrderEventHandler.cs | 12 +++--- .../EventHandlers/TrackRefreshEventHandler.cs | 1 - .../EventHandlers/TrackUpsertEventHandler.cs | 40 +++++++++---------- .../ForewarningCacheService.cs | 25 +++++++++++- .../ForewarningNotifyService.cs | 26 ++---------- .../Services/Notifies/NotifyService.cs | 12 ------ .../ProvideServices/OrderService.Link.cs | 1 - .../Services/ProvideServices/TrackService.cs | 8 ++-- .../Consts/GlobalConst.Redis.cs | 4 -- 14 files changed, 86 insertions(+), 86 deletions(-) delete mode 100644 src/SJZY.Track.Application.Contract/Services/INotifyService.cs delete mode 100644 src/SJZY.Track.Application/Services/Notifies/NotifyService.cs diff --git a/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs b/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs index 48186952..49e79b04 100644 --- a/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs +++ b/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs @@ -5,8 +5,4 @@ public struct OrderIdentifier public int OrderId { get; set; } public string OrderNo { get; set; } public int OrderType { get; set; } - - public int CustomId { get; set; } - - public bool IsTrigger { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs index 526febd8..8ef46e77 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -2,6 +2,16 @@ public class TrackChangeAfterUpdateOrderEvent { + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomId { get; set; } + /// /// 订单Id /// diff --git a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs index 905060ea..621a441c 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs @@ -3,9 +3,14 @@ public class TrackUpsertEvent { /// - /// 子系统id(操作的订单都是相同子系统下的) + /// 子系统id /// public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomId { get; set; } /// /// 订单id diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs index ce6550f1..8ee8c321 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs @@ -4,5 +4,19 @@ namespace SJZY.Track.Application.Contract.Services; public interface IForewarningCacheService { - Task> GetRulesAsync(int subSystemId); + /// + /// 获取预警规则,如果没有则返回null + /// + /// 子系统id + /// 客户id + /// + Task?> GetRulesAsync(int subSystemId, int customerId); + + /// + /// 删除规则 + /// + /// + /// + /// + Task DeleteRulesAsync(int subSystemId, int customerId); } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/INotifyService.cs b/src/SJZY.Track.Application.Contract/Services/INotifyService.cs deleted file mode 100644 index 54b8a368..00000000 --- a/src/SJZY.Track.Application.Contract/Services/INotifyService.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SJZY.Track.Application.Contract.Services; - -public interface INotifyService -{ - void SendNotification(string body); -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 0b657f6c..52f1d535 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -67,7 +67,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }); // 预警计算 - var warningOrders = orders.Select(order => MapWarningOrderDto(order, @event.TrackStatusId)).ToList(); + var warningOrders = orders.Select(order => MapWarningOrderDto(order, @event)).ToList(); _forewarningNotifyService.WarningCalculateAsync(warningOrders); } @@ -77,8 +77,6 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa return new OrderEntity { Id = order.Id, - SubSystemId = order.SubSystemId, - CustomId = order.CustomId, // 轨迹 IsCompleted = order.IsCompleted, @@ -101,14 +99,14 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }; } - private WarningOrderDto MapWarningOrderDto(OrderEntity order, int trackStatusId) + private WarningOrderDto MapWarningOrderDto(OrderEntity order, TrackChangeAfterUpdateOrderEvent @event) { return new WarningOrderDto { Id = order.Id, - TrackStatusId = trackStatusId, - SubSystemId = order.SubSystemId, - CustomerId = order.CustomId, + TrackStatusId = @event.TrackStatusId, + SubSystemId = @event.SubSystemId, + CustomerId = @event.CustomId, CargoType = order.CargoType, Month = order.CreateTime.Month, diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs index 26380b66..8afe8e0c 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs @@ -235,7 +235,6 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe OrderId = context.OrderId, OrderNo = context.OrderNo, OrderType = context.OrderType, - CustomId = context.CustomId } }, TrackRefreshData = new TrackRefreshStruct diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index cee1dc82..41808e11 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -58,6 +58,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var nextEvent = @event.DeepCopy(); nextEvent.Visited.AddRange(orderIds); nextEvent.SubSystemId = group.Key.SubSystemId; + nextEvent.CustomId = group.Key.CustomId; nextEvent.TrackRefreshData = new TrackRefreshStruct { ServiceProviderName = @event.TrackRefreshData.ServiceProviderName, @@ -88,7 +89,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe OrderId = x.OrderId, OrderNo = x.OrderNo, OrderType = x.OrderType, - CustomId = x.CustomId }).ToList(); var idx = 0; while (idx < identifiers.Count) @@ -181,6 +181,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe if(!providerDic.TryGetValue(order.OrderId,out var provider)) continue; + // todo:不要在upsert事件计算order的状态 var config = await _trackPullCacheService.GetPullParamWithContentConfigAsync(provider.SubSystemId, provider.ServiceProviderId); @@ -199,6 +200,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe, new TrackChangeAfterUpdateOrderEvent { + SubSystemId = @event.SubSystemId, + CustomId = @event.CustomId, OrderIds = canNextOrderIds.ToArray(), IsCompleted = @event.TrackRefreshData.IsCompleted, TrackContent = content.TrackContent, @@ -211,28 +214,23 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe }); // 触发轨迹推送事件(异步) - foreach (var group in @event.OrderIdentifiers - .Where(x => x.OrderId.IsIn(canNextOrderIds)) - .GroupBy(x => x.CustomId)) + var trackPushEvent = new TrackPushEvent { - var trackPushEvent = new TrackPushEvent + OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改, + SubSystemId = @event.SubSystemId, + CustomId = @event.CustomId, + OrderIds = canNextOrderIds.ToArray(), + TrackCode = @event.TrackCode, + SystemPushInfo = new SystemPushStruct { - OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改, - SubSystemId = @event.SubSystemId, - CustomId = group.Key, - OrderIds = group.Select(x => x.OrderId).ToArray(), - TrackCode = @event.TrackCode, - SystemPushInfo = new SystemPushStruct - { - TrackStatus = content.TrackStatus, - TrackContent = content.TrackContent, - TrackPlace = @event.TrackPlace, - TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone - } - }; - await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); - } + TrackStatus = content.TrackStatus, + TrackContent = content.TrackContent, + TrackPlace = @event.TrackPlace, + TrackTime = @event.TrackTime, + TrackTimeZone = @event.TrackTimeZone + } + }; + await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); } /// diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs index 289f3bbf..fdd4463c 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -6,8 +6,29 @@ namespace SJZY.Track.Application.Services.ForewarningServices; public class ForewarningCacheService: IForewarningCacheService, ISingletonDependency { - public Task> GetRulesAsync(int subSystemId) + private Dictionary> _rules = new(); + string AreaKey(int subSystemId) => $"TrackArea:{subSystemId}"; + string WarningKey(int subSystemId, int customerId) => $"TrackWarning:{subSystemId}:{customerId}"; + + // 30w => 1w => local + public async Task?> GetRulesAsync(int subSystemId, int customerId) { - throw new NotImplementedException(); + var rules = _rules.GetValueOrDefault(WarningKey(subSystemId, customerId)); + + if (rules == null) + { + // todo: 写入缓存 set str + await Task.Delay(1); + } + + return rules; + } + + // a b c del local cusomer 3 del redis cache pub del redis cache + public Task DeleteRulesAsync(int subSystemId, int customerId) + { + _rules.Remove(WarningKey(subSystemId, customerId)); + + return Task.CompletedTask; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index f4b2c418..f438a9cd 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -1,10 +1,8 @@ using FreeRedis; using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Services; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; -using SJZY.Track.Domain.Enums; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -14,16 +12,12 @@ namespace SJZY.Track.Application.Services.ForewarningServices; /// public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency { - IReadOnlyDictionary> _ruleGroupDict; - IReadOnlyDictionary> _factorDict; - private IReadOnlyDictionary _rules; - readonly INotifyService _notifyService; + private readonly ForewarningCacheService _cacheService; - public ForewarningNotifyService(INotifyService notifyService) + public ForewarningNotifyService(ForewarningCacheService cacheService) { - _notifyService = notifyService; + _cacheService = cacheService; } - /// /// 创建预警通知 /// @@ -31,7 +25,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep /// 创建的通知总量,0表示没有规则 public async Task WarningCalculateAsync(List order) { - throw new NotImplementedException(); + var rules = await _cacheService.GetRulesAsync(order[0].SubSystemId, order[0].CustomerId); } public Task DeleteForewarningNotify(WarningOrderDto order) @@ -50,21 +44,9 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep var notifyValues = notifyMembers.Select(val => new RuleNotifyValue(val)); foreach (var notifyValue in notifyValues) { - if (!_rules.TryGetValue(notifyValue.RuleId, out var rule)) - continue; - - //todo 发送通知 - _notifyService.SendNotification(""); } } - public void ClearCache() - { - _ruleGroupDict = null; - _factorDict = null; - _rules = null; - } - private List DeleteNotifyValue(ForewarningRuleItem ruleItem, int orderId) { var members = new List(); diff --git a/src/SJZY.Track.Application/Services/Notifies/NotifyService.cs b/src/SJZY.Track.Application/Services/Notifies/NotifyService.cs deleted file mode 100644 index 9365fbc9..00000000 --- a/src/SJZY.Track.Application/Services/Notifies/NotifyService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SJZY.Track.Application.Contract.Services; -using Volo.Abp.DependencyInjection; - -namespace SJZY.Track.Application.Services.Notifies; - -public class NotifyService:INotifyService, ITransientDependency -{ - public void SendNotification(string body) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs index e9554da2..1e6cb204 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs @@ -101,7 +101,6 @@ public partial class OrderService OrderId = x.Id, OrderNo = x.OrderNo, OrderType = x.OrderType, - CustomId = x.CustomId }).ToArray(), TrackCode = track.TrackCode, TrackPlace = track.TrackPlace, diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index f3d63ca2..3d76bd98 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -73,7 +73,6 @@ public partial class TrackService : ApplicationService, ITrackService OrderId = order.Id, OrderNo = order.OrderNo, OrderType = order.OrderType, - CustomId = order.CustomId } }; @event.OperationMan = name; @@ -111,18 +110,19 @@ public partial class TrackService : ApplicationService, ITrackService var name = userInfo.Data.UserName; - foreach (var group in orders.GroupBy(x => x.SubSystemId)) + foreach (var group in orders.GroupBy(x => new { x.SubSystemId, x.CustomId })) { // 新增/更新轨迹 var @event = new TrackUpsertEvent { - SubSystemId = group.Key, + SubSystemId = group.Key.SubSystemId, + CustomId = group.Key.CustomId, + OrderIdentifiers = group.Select(order => new OrderIdentifier { OrderId = order.Id, OrderNo = order.OrderNo, OrderType = input.OrderType, - CustomId = order.CustomId }).ToArray(), IsAdd = input.IsAdd, TrackCode = input.TrackCode, diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index 6f49c80d..376af72f 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -22,10 +22,6 @@ public partial class GlobalConst /// public const string TrackPullContentKeyPrefix = "TrackPullContent"; - /// - /// 规则因素缓存redis key前缀 - /// - public const string RuleFactorKeyPrefix = "RuleFactor"; /// /// 预警通知redis key前缀 From 94778ef228482c74aad6fcd071dfc0da47abfc98 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Mon, 29 Jul 2024 18:10:48 +0800 Subject: [PATCH 48/60] =?UTF-8?q?add=EF=BC=9A=E9=A2=84=E8=AD=A6=E8=AE=A1?= =?UTF-8?q?=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Forewarning/ForewarningRuleCacheEntry.cs | 2 +- .../Dtos/Forewarning/WarningDto.cs | 17 ++ .../Forewarning/WarningNotifyCacheEntry.cs | 32 ++++ .../Dtos/Forewarning/WarningOrderDto.cs | 13 +- .../Services/IForewarningNotifyService.cs | 10 +- ...TrackChangeAfterUpdateOrderEventHandler.cs | 60 +++---- .../ForewarningNotifyService.cs | 150 +++++++++++------- .../Consts/GlobalConst.Redis.cs | 5 +- .../Dtos/Forewarning/ForewarningRuleItem.cs | 26 --- .../Dtos/Forewarning/RuleNotifyValue.cs | 40 ----- 10 files changed, 181 insertions(+), 174 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs rename src/{SJZY.Track.Domain => SJZY.Track.Application.Contract}/Dtos/Forewarning/WarningOrderDto.cs (74%) delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs delete mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs index 09ab3e1d..71d402b6 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs @@ -50,7 +50,7 @@ public class ForewarningRuleCacheEntry /// /// 区域 /// - public List? AreaId { get; set; } + public AreaCacheEntry? Area { get; set; } /// /// 是否中转 diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs new file mode 100644 index 00000000..f911768c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs @@ -0,0 +1,17 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningDto +{ + /// + /// 当前轨迹状态 + /// + public int TrackStatusId { get; set; } + + public int SubSystemId { get; set; } + + public int CustomerId { get; set; } + + public List Orders { get; set; } = new(); +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs new file mode 100644 index 00000000..71112bb8 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs @@ -0,0 +1,32 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningNotifyCacheEntry +{ + /// + /// 订单id + /// + public int OrderId { get; set; } + + /// + /// 规则id + /// + public int RuleId { get; set; } + + public WarningNotifyCacheEntry(int orderId, int ruleId) + { + RuleId = ruleId; + OrderId = orderId; + } + + public WarningNotifyCacheEntry(string notifyValue) + { + var values = notifyValue.Split(':'); + OrderId = int.Parse(values[0]); + RuleId = int.Parse(values[1]); + } + + public override string ToString() + { + return $"{OrderId}:{RuleId}"; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningOrderDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs similarity index 74% rename from src/SJZY.Track.Domain/Dtos/Forewarning/WarningOrderDto.cs rename to src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs index 4cdc5a91..c9a395b9 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningOrderDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; public class WarningOrderDto { @@ -7,18 +7,9 @@ public class WarningOrderDto /// public int Id { get; set; } - /// - /// 当前轨迹状态 - /// - public int TrackStatusId { get; set; } - - public int SubSystemId { get; set; } - - public int CustomerId { get; set; } - public string? CargoType { get; set; } - public int? Month { get; set; } + public int Month { get; set; } public bool? IsTransit { get; set; } diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs index 8830f610..2709a84c 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs @@ -1,3 +1,4 @@ +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Application.Contract.Services; @@ -13,14 +14,7 @@ public interface IForewarningNotifyService /// /// 预警订单模型。 /// 创建操作的结果,以整数形式返回。 - Task WarningCalculateAsync(List order); - - /// - /// 删除预警通知。 - /// - /// 预警订单模型。 - /// 删除操作的结果,以整数形式返回。 - Task DeleteForewarningNotify(WarningOrderDto order); + Task WarningCalculateAsync(WarningDto order); /// /// 发送通知。 diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 52f1d535..3e96a3b5 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -1,4 +1,5 @@ using DotNetCore.CAP; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; @@ -28,7 +29,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa if (orders.Count == 0) return; var updateOrders = new List(); - + foreach (var order in orders) { if (order.LatestTrackContent != @event.TrackContent) @@ -65,11 +66,34 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, x.LatestTrackTimeZone }); - + // 预警计算 - var warningOrders = orders.Select(order => MapWarningOrderDto(order, @event)).ToList(); - - _forewarningNotifyService.WarningCalculateAsync(warningOrders); + await _forewarningNotifyService.WarningCalculateAsync( BuiltWarningDto(orders, @event)); + } + + private WarningDto BuiltWarningDto(List orders, TrackChangeAfterUpdateOrderEvent @event) + { + return new WarningDto + { + TrackStatusId = @event.TrackStatusId, + SubSystemId = @event.SubSystemId, + CustomerId = @event.CustomId, + Orders = orders.Select(order => new WarningOrderDto + { + Id = order.Id, + + CargoType = order.CargoType, + Month = order.CreateTime.Month, + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode, + + ArrivalCountry = order.ArrivalCountry, + ArrivalProvince = order.ArrivalProvince, + ArrivalCity = order.ArrivalCity, + ArrivalPostCode = order.ArrivalPostCode, + }).ToList() + }; } private OrderEntity MapOrderSummary(OrderEntity order) @@ -77,7 +101,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa return new OrderEntity { Id = order.Id, - + // 轨迹 IsCompleted = order.IsCompleted, LatestTrackContent = order.LatestTrackContent, @@ -85,7 +109,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa LatestTrackPlace = order.LatestTrackPlace, LatestTrackTime = order.LatestTrackTime, LatestTrackTimeZone = order.LatestTrackTimeZone, - + // 因素 CargoType = order.CargoType, CreateTime = order.CreateTime, @@ -98,26 +122,4 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa ProductCode = order.ProductCode }; } - - private WarningOrderDto MapWarningOrderDto(OrderEntity order, TrackChangeAfterUpdateOrderEvent @event) - { - return new WarningOrderDto - { - Id = order.Id, - TrackStatusId = @event.TrackStatusId, - SubSystemId = @event.SubSystemId, - CustomerId = @event.CustomId, - - CargoType = order.CargoType, - Month = order.CreateTime.Month, - IsTransit = order.IsTransit, - LeavePort = order.LeavePort, - ProductCode = order.ProductCode, - - ArrivalCountry = order.ArrivalCountry, - ArrivalProvince = order.ArrivalProvince, - ArrivalCity = order.ArrivalCity, - ArrivalPostCode = order.ArrivalPostCode, - }; - } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index f438a9cd..75f44fec 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -1,8 +1,8 @@ using FreeRedis; using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Dtos.Forewarning; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -18,84 +18,122 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep { _cacheService = cacheService; } + /// /// 创建预警通知 /// - /// 创建预警通知需要的订单信息 + /// 创建预警通知需要的订单信息 /// 创建的通知总量,0表示没有规则 - public async Task WarningCalculateAsync(List order) + public async Task WarningCalculateAsync(WarningDto dto) { - var rules = await _cacheService.GetRulesAsync(order[0].SubSystemId, order[0].CustomerId); + if (dto.Orders.Count == 0) return; + + var rules = await _cacheService.GetRulesAsync(dto.SubSystemId, dto.CustomerId); + if (rules == null || rules.Count == 0) return; + + var zMembers = new List(); + var members = new List(); + foreach (var order in dto.Orders) + { + MatchRule( + rules.Where(rule => rule.StartTrackStatusId == dto.TrackStatusId).ToList(), + order + ).ForEach(rule => + { + var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(rule.WarnTimeSpan)); + var entry = new WarningNotifyCacheEntry(rule.Id, order.Id); + var notifyValue = new ZMember(entry.ToString(), notifyTimestamp); + zMembers.Add(notifyValue); + }); + + var endingRules = MatchRule( + rules.Where(rule => rule.EndTrackStatusId == dto.TrackStatusId).ToList(), + order + ); + + foreach (var rule in endingRules) + { + var entry = new WarningNotifyCacheEntry(rule.Id, order.Id); + var member = entry.ToString(); + // todo: pipeline optimize? + var score = await RedisHelper.Client.ZScoreAsync(GlobalConst.ForewarningNotifyKey, member); + // tips: score is null 说明发生ending时,没有匹配到规则,所以没有add到set,不需要删除 + if (score != null && (long)score > GetTimestamp(DateTime.Now)) + { + members.Add(member); + } + } + } + + await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKey, zMembers.ToArray()); + await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKey, members.ToArray()); } - public Task DeleteForewarningNotify(WarningOrderDto order) + private static List MatchRule(List rules, + WarningOrderDto order) { - throw new NotImplementedException(); + var res = new List(); + foreach (var rule in rules) + { + if (rule.IsTransit != null) + { + if (order.IsTransit != rule.IsTransit) continue; + } + + if (!rule.CargoType.IsNullOrEmpty()) + { + if (order.CargoType != rule.CargoType) continue; + } + + if (!rule.LeavePort.IsNullOrEmpty()) + { + if (order.LeavePort != rule.LeavePort) continue; + } + + if (!rule.ProductCode.IsNullOrEmpty()) + { + if (order.ProductCode != rule.ProductCode) continue; + } + + if (!rule.Months.IsNullOrEmpty()) + { + if (!order.Month.IsIn(rule.Months)) continue; + } + + if (rule.Area != null) + { + if (order.ArrivalCountry != rule.Area.Country) continue; + if (!rule.Area.LeftPostcode.IsNullOrEmpty() && !rule.Area.RightPostcode.IsNullOrEmpty()) + { + // todo: 参考小包的邮编匹配 + } + + if (!rule.Area.City.IsNullOrEmpty() && order.ArrivalCity != rule.Area.City) continue; + if (!rule.Area.Province.IsNullOrEmpty() && order.ArrivalProvince != rule.Area.Province) continue; + } + + res.Add(rule); + } + + return res; } public void SendNotification(int intervalMinute) { var currentTimestamp = GetTimestamp(DateTime.Now); var notifyMembers = - RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKeyPrefix, 0, currentTimestamp); + RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKey, 0, currentTimestamp); if (notifyMembers == null || notifyMembers.Length == 0) return; - var notifyValues = notifyMembers.Select(val => new RuleNotifyValue(val)); + var notifyValues = notifyMembers.Select(val => new WarningNotifyCacheEntry(val)); foreach (var notifyValue in notifyValues) { } } - private List DeleteNotifyValue(ForewarningRuleItem ruleItem, int orderId) - { - var members = new List(); - for (var index = 0; index < ruleItem.Count; index++) - { - var notifyValue = NotifyValue(ruleItem, orderId, index); - members.Add(notifyValue); - } - - return members; - } - - private async ValueTask ExecuteRule(List rules, int orderId) - { - var members = new List(); - foreach (var rule in rules) - { - var notifys = ExecuteRule(rule, orderId); - members.AddRange(notifys); - } - - await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKeyPrefix, members.ToArray()); - return members.Count; - } - - private List ExecuteRule(ForewarningRuleItem ruleItem, int orderId) - { - var members = new List(); - var intervalMinute = 60 * ((ruleItem.Timeliness - ruleItem.Remind) / ruleItem.Count); // 间隔多少分钟 - - for (var index = 0; index < ruleItem.Count; index++) - { - var notifyTime = (ruleItem.Remind * 60) + intervalMinute * index; - var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(notifyTime)); - var notifyValue = new ZMember(NotifyValue(ruleItem, orderId, index), notifyTimestamp); - members.Add(notifyValue); - } - - return members; - } - - private long GetTimestamp(DateTime dateTime) + private static long GetTimestamp(DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); } - - private string NotifyValue(ForewarningRuleItem ruleItem, int orderId, int sort) - { - var result = new RuleNotifyValue(ruleItem.Id, orderId, sort, ruleItem.TrackEnd); - return result.ToString(); - } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index 376af72f..9b29d958 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -22,11 +22,10 @@ public partial class GlobalConst /// public const string TrackPullContentKeyPrefix = "TrackPullContent"; - /// - /// 预警通知redis key前缀 + /// 预警通知redis key /// - public const string ForewarningNotifyKeyPrefix = "ForewarningNotity"; + public const string ForewarningNotifyKey = "ForewarningNotify"; /// /// kpi区域redis key前缀 diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs deleted file mode 100644 index 9e03f6c2..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/ForewarningRuleItem.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public record struct ForewarningRuleItem:IForewarningFactorValue -{ - public int Id { get; set; } - - public int CustomerId { get; set; } - - public int SystemId { get; set; } - public int RuleId { get; set; } - public float Remind { get; set; } - public float Timeliness { get; set; } - public int Count { get; set; } - public int TrackStart { get; set; } - public int TrackEnd { get; set; } - public string? CargoType { get; set; } - public int? Month { get; set; } - public int? Area { get; set; } - public bool? IsTransit { get; set; } - public string? LeavePort { get; set; } - public string? ProductCode { get; set; } - - public string Conect { get; set; } - - public string Template { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs deleted file mode 100644 index eda39cc7..00000000 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleNotifyValue.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Forewarning; - -public class RuleNotifyValue -{ - public int RuleId { get; set; } - - public int OrderId { get; set; } - - /// - /// 第几次通知 - /// - public int Count { get; set; } - - /// - /// 结束轨迹状态 - /// - public int TrackEnd { get; set; } - - public RuleNotifyValue(int ruleId, int orderId, int count, int trackEnd) - { - RuleId = ruleId; - OrderId = orderId; - Count = count; - TrackEnd = trackEnd; - } - - public RuleNotifyValue(string notifyValue) - { - var values = notifyValue.Split(':'); - RuleId = int.Parse(values[0]); - OrderId = int.Parse(values[1]); - Count = int.Parse(values[2]); - TrackEnd = int.Parse(values[3]); - } - - public override string ToString() - { - return $"{RuleId}:{OrderId}:{Count}:{TrackEnd}"; - } -} \ No newline at end of file From 2cea1a791222d2a2df5afb1d7be34676d7cd2024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Mon, 29 Jul 2024 18:58:36 +0800 Subject: [PATCH 49/60] =?UTF-8?q?feat:=20=E8=BD=A8=E8=BF=B9=E9=A2=84?= =?UTF-8?q?=E8=AD=A6=E8=A7=84=E5=88=99=E7=BC=93=E5=AD=98=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SJZY.Track.Api/SjzyTrackApiModule.cs | 2 + .../Events/ModifyWarningEvent.cs | 23 +++ .../Services/IForewarningCacheService.cs | 12 ++ .../HostServices/RedisHostService.cs | 46 +++++ .../ForewarningCacheService.cs | 188 +++++++++++++++++- .../KpiAreaCacheService.cs | 21 +- .../ForewarningServices/KpiAreaService.cs | 16 +- .../IWarningRepository.cs | 7 + .../KPIAreaAggregate/IKpiAreaRepository.cs | 2 +- .../Consts/GlobalConst.Redis.cs | 15 ++ .../Dtos/Forewarning/KpiAreaInfo.cs | 25 +++ .../Dtos/Forewarning/WarningRuleCacheDto.cs | 20 ++ .../Repositories/KpiAreaRepository.cs | 14 +- .../Repositories/WarningRepository.cs | 26 +++ 14 files changed, 387 insertions(+), 30 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs create mode 100644 src/SJZY.Track.Application/HostServices/RedisHostService.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs diff --git a/src/SJZY.Track.Api/SjzyTrackApiModule.cs b/src/SJZY.Track.Api/SjzyTrackApiModule.cs index 13d9633a..a9cd95ae 100644 --- a/src/SJZY.Track.Api/SjzyTrackApiModule.cs +++ b/src/SJZY.Track.Api/SjzyTrackApiModule.cs @@ -9,6 +9,7 @@ using SJZY.Expand.ABP.Core.Prometheus; using SJZY.Expand.ABP.Core.Redis; using SJZY.Expand.ABP.Core.Swagger; using SJZY.Track.Application; +using SJZY.Track.Application.HostServices; using SJZY.Track.Repository; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; @@ -62,6 +63,7 @@ namespace SJZY.Track.Api Configure(options => { options.IsEnabled = false; }); context.Services.AddRedis(); + context.Services.AddHostedService(); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs b/src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs new file mode 100644 index 00000000..265f00c2 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs @@ -0,0 +1,23 @@ +namespace SJZY.Track.Application.Contract.Events; + +/// +/// redis 的发布订阅事件 +/// +public class ModifyWarningEvent:RedisEvent +{ + public string Key { get; set; } +} + +public class RedisEvent : IRedisEvent +{ + public string EventType { get; set; } +} + + +/// +/// 简单的事件接口,后续可以根据需要扩展 +/// +public interface IRedisEvent +{ + string EventType { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs index 8ee8c321..d7743c32 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs @@ -19,4 +19,16 @@ public interface IForewarningCacheService /// /// Task DeleteRulesAsync(int subSystemId, int customerId); + + /// + /// 重置本地缓存 + /// + /// + Task Clear(); + + /// + /// 清除redis 缓存 + /// + /// + Task ClearRedis(); } \ No newline at end of file diff --git a/src/SJZY.Track.Application/HostServices/RedisHostService.cs b/src/SJZY.Track.Application/HostServices/RedisHostService.cs new file mode 100644 index 00000000..702afb51 --- /dev/null +++ b/src/SJZY.Track.Application/HostServices/RedisHostService.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.Hosting; +using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Consts; + +namespace SJZY.Track.Application.HostServices; + +public class RedisHostService:IHostedService +{ + readonly IForewarningCacheService _forewarningCacheService; + + public RedisHostService(IForewarningCacheService forewarningCacheService) + { + _forewarningCacheService = forewarningCacheService; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + // 订阅频道 + RedisHelper.Client.Subscribe(GetKey(), Subscribe); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + RedisHelper.Client.UnSubscribe(GetKey()); + return Task.CompletedTask; + } + + private void Subscribe(string message,object value) + { + if (value is string) + { + // 暂时只处理一个事件,不做反序列化 + //var instance = Newtonsoft.Json.JsonConvert.DeserializeObject(value as string); + } + + _forewarningCacheService.Clear(); + } + + private string GetKey() + { + return $"{GlobalConst.PublishNotifyChannelKey}"; + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs index fdd4463c..317e6c3a 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -1,29 +1,133 @@ +using FreeRedis; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; public class ForewarningCacheService: IForewarningCacheService, ISingletonDependency { - private Dictionary> _rules = new(); - string AreaKey(int subSystemId) => $"TrackArea:{subSystemId}"; - string WarningKey(int subSystemId, int customerId) => $"TrackWarning:{subSystemId}:{customerId}"; + readonly IKpiAreaRepository _kpiAreaRepository; + readonly IWarningRepository _warningRepository; + const string GlobalKpiAreaLockKey = "KKpiAreaLockKey_GlobalLock"; + private const string GlobalWaningLockKey = "GlobalWaningLockKey_GlobalLock"; + + private Dictionary> _rules = new(); + private Dictionary>? _areas = new(); + readonly object _lock = new object(); + + public ForewarningCacheService(IKpiAreaRepository kpiAreaRepository, IWarningRepository warningRepository) + { + _kpiAreaRepository = kpiAreaRepository; + _warningRepository = warningRepository; + } + + + string WarningKey(int subSystemId, int customerId) => $"{GlobalConst.TrackWarningKeyPrefix}:{subSystemId}:{customerId}"; + + string WarningKey() => $"{GlobalConst.TrackWarningKeyPrefix}:all"; + + string AreaKey() + { + return $"{GlobalConst.TrackAreaKeyPrefix}"; + } + // 30w => 1w => local public async Task?> GetRulesAsync(int subSystemId, int customerId) { - var rules = _rules.GetValueOrDefault(WarningKey(subSystemId, customerId)); + var key = WarningKey(subSystemId, customerId); + var rules = _rules.GetValueOrDefault(key); if (rules == null) - { - // todo: 写入缓存 set str - await Task.Delay(1); + { + return await GetRules(subSystemId, customerId); } return rules; } + private List WriteRules(List rules) + { + List result = new List(); + foreach (var item in rules) + { + List? areaList = null; + if (item.AreaId.HasValue) + { + areaList = GetAreaInfoByAreaId(item.AreaId!.Value); + } + + var entry = new ForewarningRuleCacheEntry + { + Id = item.Id, + WarningId = item.WarningId, + TotalTimeSpan = item.TotalTimeSpan, + WarnTimeSpan = item.WarnTimeSpan, + WarnCount = item.WarnCount, + StartTrackStatusId = item.StartTrackStatusId, + EndTrackStatusId = item.EndTrackStatusId, + CargoType = item.CargoType, + Months = string.IsNullOrEmpty(item.Months)?new List():item.Months.Split('/').Select(int.Parse).ToList(), + IsTransit = item.IsTransit, + AreaId = areaList, + ProductCode = item.ProductCode, + LeavePort = item.LeavePort + }; + + result.Add(entry); + } + + return result; + } + + private async Task?> GetRules(int systemId, int customerId) + { + var key = WarningKey(); + var result = RedisHelper.Client.Get>(key); + if (result != null) + { + // 非线程安全,需要加锁 + lock (_lock) + { + _rules = result.GroupBy(val => WarningKey(val.SystemId, val.CustomerId)) + .ToDictionary(val => val.Key, val => WriteRules(val.ToList())); + + return _rules.GetValueOrDefault(WarningKey(systemId,customerId)); + } + } + + // 非线程安全,需要加锁 + using (RedisHelper.Client.Lock(GlobalWaningLockKey, 20)) + { + var ruleResult = _rules.GetValueOrDefault(WarningKey(systemId,customerId)); + if (ruleResult == null) + { + var warnings = await _warningRepository.GetAllWarningRule(); + if (warnings == null || warnings.Count == 0) + { + RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); + return new List(); + } + + RedisHelper.Client.Set(key, warnings); + _rules = warnings.GroupBy(val => WarningKey(val.SystemId, val.CustomerId)) + .ToDictionary(val => val.Key, val => WriteRules(val.ToList())); + + return _rules.GetValueOrDefault(WarningKey(systemId,customerId)); + } + + return ruleResult; + } + + } + // a b c del local cusomer 3 del redis cache pub del redis cache public Task DeleteRulesAsync(int subSystemId, int customerId) { @@ -31,4 +135,74 @@ public class ForewarningCacheService: IForewarningCacheService, ISingletonDepend return Task.CompletedTask; } + + private List? GetAreaInfoByAreaId(int areaId) + { + if (_areas == null || _areas.Count == 0) + { + var areas = GetAreas(); + if(areas==null || areas.Count==0) return null; + _areas = areas.GroupBy(x => x.AreaId) + .ToDictionary(x => x.Key, x => x.Select(KpiAreaInfoToEntry).ToList()); + } + + return _areas.GetValueOrDefault(areaId); + } + + AreaCacheEntry KpiAreaInfoToEntry(KpiAreaInfo model) + { + return new AreaCacheEntry + { + Country = model.Country, + Province = model.Province, + City = model.City, + LeftPostcode = model.LeftPostcode, + RightPostcode = model.RightPostcode + }; + } + + /// + /// 获取所有区域 + /// + /// + private List? GetAreas() + { + var key = AreaKey(); + var result = RedisHelper.Client.Get>(key); + if (result == null) + { + using (RedisHelper.Client.Lock(GlobalKpiAreaLockKey, 20)) + { + result = RedisHelper.Client.Get>(key); + if (result != null) return new List(); + + var kpiArea = _kpiAreaRepository.GetAllAreaInfos(); + if (kpiArea == null) + { + RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); + return new List(); + } + + RedisHelper.Client.Set(key, kpiArea); + return kpiArea; + } + } + + return result; + } + + public Task Clear() + { + _rules?.Clear(); + _areas?.Clear(); + return Task.CompletedTask; + } + + public Task ClearRedis() + { + RedisHelper.Client.Del(WarningKey()); + RedisHelper.Client.Del(AreaKey()); + return Task.CompletedTask; + } + } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs index 65accbcf..4728dcf6 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs @@ -22,25 +22,8 @@ public class KpiAreaCacheService:IKpiAreaCacheService,ITransientDependency return $"{GlobalConst.KpiAreaKeyPrefix}:{systemId}:{country}"; } - public async Task GetKpiArea(int systemId, string country) + public Task GetKpiArea(int systemId, string country) { - var key = GetKey(systemId, country); - var result = RedisHelper.Client.Get(key); - if (result == null) - { - using (var globalLock = RedisHelper.Client.Lock(GlobalKpiAreaLockKey, 10)) - { - result = RedisHelper.Client.Get(key); - if (result != null) return; - - //todo 转换成KpiAreaInfo - var kpiArea =await _kpiAreaRepository.GetAllAreaInfos(); - if (kpiArea == null) - { - return; - } - RedisHelper.Client.Set(key, kpiArea, TimeSpan.FromSeconds(20)); - } - } + throw new NotImplementedException(); } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs index 593467ef..a0057a41 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -1,4 +1,7 @@ +using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -8,10 +11,12 @@ namespace SJZY.Track.Application.Services.ForewarningServices; public class KpiAreaService : ApplicationService { private readonly IKpiAreaRepository _ruleAreaRepository; + private readonly IForewarningCacheService _forewarningCacheService; - public KpiAreaService(IKpiAreaRepository ruleAreaRepository) + public KpiAreaService(IKpiAreaRepository ruleAreaRepository, IForewarningCacheService forewarningCacheService) { _ruleAreaRepository = ruleAreaRepository; + _forewarningCacheService = forewarningCacheService; } /// @@ -37,6 +42,8 @@ public class KpiAreaService : ApplicationService { var ruleAreaEntity = ObjectMapper.Map(input); var ruleInfoId = await _ruleAreaRepository.AddAreaInfoAsync(ruleAreaEntity); + await _forewarningCacheService.ClearRedis(); + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); return new UnifyResultDto(true, ruleInfoId, "添加成功"); } @@ -49,6 +56,8 @@ public class KpiAreaService : ApplicationService public async ValueTask DeleteKpiArea(int id) { await _ruleAreaRepository.DeleteArea(id); + await _forewarningCacheService.ClearRedis(); + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear locl cache"); return new UnifyResultDto(true, "删除成功"); } @@ -61,6 +70,8 @@ public class KpiAreaService : ApplicationService public async ValueTask DeleteKpiAreaInfo(int id) { await _ruleAreaRepository.DeleteAreaInfo(id); + await _forewarningCacheService.ClearRedis(); + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); return new UnifyResultDto(true, "删除成功"); } @@ -101,6 +112,9 @@ public class KpiAreaService : ApplicationService var ruleAreaEntity = ObjectMapper.Map(input, areaInfo); await _ruleAreaRepository.UpdateAreaInfoAsync(ruleAreaEntity); + + await _forewarningCacheService.ClearRedis(); + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); return new UnifyResultDto(true, "更新成功"); } diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs index efa73bbd..a864c05a 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs @@ -59,4 +59,11 @@ public interface IWarningRepository : IBasicRepository /// /// Task GetByIdAsync(int warningId); + + /// + /// 获取预警规则列表 + /// + /// + Task?> GetAllWarningRule(); + } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs index c3c906d9..21d15342 100644 --- a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs @@ -64,5 +64,5 @@ public interface IKpiAreaRepository : IBasicRepository /// 获取所有区域信息 /// /// - Task> GetAllAreaInfos(); + List? GetAllAreaInfos(); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index 376af72f..808d772a 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -42,4 +42,19 @@ public partial class GlobalConst /// 港口时区redis key前缀 /// public const string PortTimezoneKeyPrefix = "PortTimezone"; + + /// + /// 发布订阅通知频道Key + /// + public const string PublishNotifyChannelKey = "PublishNotifyChannel"; + + /// + /// 轨迹区域reids key + /// + public const string TrackAreaKeyPrefix = "TrackArea"; + + /// + /// 轨迹预警数据redis key前缀 + /// + public const string TrackWarningKeyPrefix = "TrackWarning"; } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs index a9273783..eafc4d09 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs @@ -2,5 +2,30 @@ namespace SJZY.Track.Domain.Dtos.Forewarning; public class KpiAreaInfo { + public int AreaId { get; set; } + /// + /// 国家或地区 + /// + public string Country { get; set; } = null!; + + /// + /// 省份 + /// + public string? Province { get; set; } + + /// + /// 城市 + /// + public string? City { get; set; } + + /// + /// 开始邮编 + /// + public string? LeftPostcode { get; set; } + + /// + /// 截止邮编 + /// + public string? RightPostcode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs new file mode 100644 index 00000000..43b6b25c --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs @@ -0,0 +1,20 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningRuleCacheDto +{ + public int Id { get; set; } + public int SystemId { get; set; } + public int CustomerId { get; set; } + public int WarningId { get; set; } + public float TotalTimeSpan { get; set; } + public float WarnTimeSpan { get; set; } + public int WarnCount { get; set; } + public int StartTrackStatusId { get; set; } + public int EndTrackStatusId { get; set; } + public string? CargoType { get; set; } + public string? Months { get; set; } + public int? AreaId { get; set; } + public bool? IsTransit { get; set; } + public string? LeavePort { get; set; } + public string? ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs index f6226432..e2008c27 100644 --- a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -94,8 +94,18 @@ public class KpiAreaRepository : BasicRepository, IKpiAreaReposi /// 获取所有区域信息 /// /// - public Task> GetAllAreaInfos() + public List GetAllAreaInfos() { - return Context.Queryable().ToListAsync(); + return Context.Queryable() + .Select((x)=>new KpiAreaInfo + { + AreaId = x.AreaId, + Country = x.CountryCode, + LeftPostcode = x.LeftPostcode, + City = x.City, + Province = x.Province, + RightPostcode = x.RightPostcode + }) + .ToList(); } } \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs index fe25f1d7..23286a59 100644 --- a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs @@ -109,4 +109,30 @@ public class WarningRepository : BasicRepository, IWarningReposit return warning; } + + public Task?> GetAllWarningRule() + { + return Context.Queryable() + .InnerJoin((a, b) => a.WarningId == b.Id) + .Where((a,b)=>b.IsEnable) + .Select((a,b)=>new WarningRuleCacheDto + { + Id = a.Id, + WarningId = a.WarningId, + TotalTimeSpan = a.TotalTimeSpan, + WarnTimeSpan = a.WarnTimeSpan, + WarnCount = a.WarnCount, + StartTrackStatusId = a.StartTrackStatusId, + EndTrackStatusId = a.EndTrackStatusId, + CargoType = a.CargoType, + Months = a.Months, + AreaId = a.AreaId, + IsTransit = a.IsTransit, + LeavePort = a.LeavePort, + ProductCode = a.ProductCode, + CustomerId = b.CustomerId, + SystemId = b.SubSystemId + }) + .ToListAsync(); + } } \ No newline at end of file From 67811638a9bc2b911e02fcc8ea94c971d4e4b047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Mon, 29 Jul 2024 19:03:41 +0800 Subject: [PATCH 50/60] =?UTF-8?q?feat:=20=E5=A4=84=E7=90=86=E5=86=B2?= =?UTF-8?q?=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Forewarning/ForewarningRuleCacheEntry.cs | 5 +++++ .../Services/ForewarningServices/ForewarningCacheService.cs | 2 +- .../Services/ForewarningServices/KpiAreaService.cs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs index 71d402b6..fd9e30e2 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs @@ -51,6 +51,11 @@ public class ForewarningRuleCacheEntry /// 区域 /// public AreaCacheEntry? Area { get; set; } + + /// + /// 区域 + /// + public List? Areas { get; set; } /// /// 是否中转 diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs index 317e6c3a..a79684d6 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -76,7 +76,7 @@ public class ForewarningCacheService: IForewarningCacheService, ISingletonDepend CargoType = item.CargoType, Months = string.IsNullOrEmpty(item.Months)?new List():item.Months.Split('/').Select(int.Parse).ToList(), IsTransit = item.IsTransit, - AreaId = areaList, + Areas = areaList, ProductCode = item.ProductCode, LeavePort = item.LeavePort }; diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs index a0057a41..3b693a1c 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -57,7 +57,7 @@ public class KpiAreaService : ApplicationService { await _ruleAreaRepository.DeleteArea(id); await _forewarningCacheService.ClearRedis(); - await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear locl cache"); + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); return new UnifyResultDto(true, "删除成功"); } From 84e2764ebec087a9b0d9e5020a4f3b0680f42c51 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Tue, 30 Jul 2024 15:13:55 +0800 Subject: [PATCH 51/60] temp --- ...TrackChangeAfterUpdateOrderEventHandler.cs | 58 +++++++++---------- .../ForewarningNotifyService.cs | 6 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 3e96a3b5..056d1748 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -24,7 +24,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] public async Task ConsumerAsync(TrackChangeAfterUpdateOrderEvent @event) { - var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id), x => MapOrderSummary(x)); + var orders = await GetOrdersAsync(@event.OrderIds); if (orders.Count == 0) return; @@ -68,7 +68,34 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }); // 预警计算 - await _forewarningNotifyService.WarningCalculateAsync( BuiltWarningDto(orders, @event)); + await _forewarningNotifyService.WarningCalculateAsync(BuiltWarningDto(orders, @event)); + } + + private async Task> GetOrdersAsync(int[] orderIds) + { + return await _orderRepository.GetListAsync(order => orderIds.Contains(order.Id), order => new OrderEntity + { + Id = order.Id, + + // 轨迹 + IsCompleted = order.IsCompleted, + LatestTrackContent = order.LatestTrackContent, + LatestTrackEnContent = order.LatestTrackEnContent, + LatestTrackPlace = order.LatestTrackPlace, + LatestTrackTime = order.LatestTrackTime, + LatestTrackTimeZone = order.LatestTrackTimeZone, + + // 因素 + CargoType = order.CargoType, + CreateTime = order.CreateTime, + ArrivalCountry = order.ArrivalCountry, + ArrivalProvince = order.ArrivalProvince, + ArrivalCity = order.ArrivalCity, + ArrivalPostCode = order.ArrivalPostCode, + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode + }); } private WarningDto BuiltWarningDto(List orders, TrackChangeAfterUpdateOrderEvent @event) @@ -95,31 +122,4 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa }).ToList() }; } - - private OrderEntity MapOrderSummary(OrderEntity order) - { - return new OrderEntity - { - Id = order.Id, - - // 轨迹 - IsCompleted = order.IsCompleted, - LatestTrackContent = order.LatestTrackContent, - LatestTrackEnContent = order.LatestTrackEnContent, - LatestTrackPlace = order.LatestTrackPlace, - LatestTrackTime = order.LatestTrackTime, - LatestTrackTimeZone = order.LatestTrackTimeZone, - - // 因素 - CargoType = order.CargoType, - CreateTime = order.CreateTime, - ArrivalCountry = order.ArrivalCountry, - ArrivalProvince = order.ArrivalProvince, - ArrivalCity = order.ArrivalCity, - ArrivalPostCode = order.ArrivalPostCode, - IsTransit = order.IsTransit, - LeavePort = order.LeavePort, - ProductCode = order.ProductCode - }; - } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index 75f44fec..003d6cf6 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -51,10 +51,10 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep order ); - foreach (var rule in endingRules) + foreach (var member in endingRules.Select(rule => + new WarningNotifyCacheEntry(rule.Id, order.Id).ToString()) + ) { - var entry = new WarningNotifyCacheEntry(rule.Id, order.Id); - var member = entry.ToString(); // todo: pipeline optimize? var score = await RedisHelper.Client.ZScoreAsync(GlobalConst.ForewarningNotifyKey, member); // tips: score is null 说明发生ending时,没有匹配到规则,所以没有add到set,不需要删除 From 6df23b96e68a5837789b6b57f1b7a348a2345ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Tue, 30 Jul 2024 15:22:25 +0800 Subject: [PATCH 52/60] =?UTF-8?q?feat:=20=E8=BF=81=E7=A7=BBorder=20pull=20?= =?UTF-8?q?trigger=20=E6=A0=87=E7=AD=BE=E8=B5=8B=E5=80=BC=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrackChangeAfterUpdateOrderEvent.cs | 4 +- ...TrackChangeAfterUpdateOrderEventHandler.cs | 37 +++++++++++++++---- .../EventHandlers/TrackUpsertEventHandler.cs | 35 ++---------------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs index 8ef46e77..385b01f1 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -53,7 +53,7 @@ public class TrackChangeAfterUpdateOrderEvent public float TrackTimeZone { get; set; } /// - /// 根据配置规则,标记拉取时需要的订单Id + /// 轨迹内容代码 /// - public int[] TriggerPullOrderIds { get; set; } = Array.Empty(); + public string? TrackCode { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 3e96a3b5..39c202ba 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -5,6 +5,8 @@ using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Dtos.Order; +using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.CAP.EventHandlers; @@ -13,12 +15,16 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa { private readonly IOrderRepository _orderRepository; private readonly IForewarningNotifyService _forewarningNotifyService; - + private readonly ITrackPullCacheService _trackPullCacheService; + private readonly IProvideQueries _provideQueries; + public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, - IForewarningNotifyService forewarningNotifyService) + IForewarningNotifyService forewarningNotifyService, ITrackPullCacheService trackPullCacheService, IProvideQueries provideQueries) { _orderRepository = orderRepository; _forewarningNotifyService = forewarningNotifyService; + _trackPullCacheService = trackPullCacheService; + _provideQueries = provideQueries; } [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] @@ -29,7 +35,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa if (orders.Count == 0) return; var updateOrders = new List(); - + var providerDic= await GetProviderDic(@event.OrderIds); foreach (var order in orders) { if (order.LatestTrackContent != @event.TrackContent) @@ -47,12 +53,17 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa order.IsCompleted = @event.IsCompleted; } - // 触发拉取节点 - if (@event.TriggerPullOrderIds.Contains(order.Id)) + if (providerDic.TryGetValue(order.Id, out var provider)) { - order.IsTriggerPull = 1; + var config = await _trackPullCacheService.GetPullParamWithContentConfigAsync(provider.SubSystemId, provider.ServiceProviderId); + + if (config!=null && config.ParamConfig!=null && config.ParamConfig.TrackContentCode == @event.TrackCode) + { + // 触发拉取节点 + order.IsTriggerPull = 1; + } } - + order.LatestTrackContent = @event.TrackContent; order.LatestTrackEnContent = @event.TrackEnContent; order.LatestTrackPlace = @event.TrackPlace; @@ -122,4 +133,16 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa ProductCode = order.ProductCode }; } + + /// + /// 获取服务商字典 + /// + /// + /// + private async Task> GetProviderDic(int[] orderIds) + { + var providerList = await _provideQueries.FindOrderWithServiceProviderAsync(orderIds); + return providerList.GroupBy(val => val.OrderId) + .ToDictionary(val => val.Key, val => val.First()); + } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index 41808e11..5e73128b 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -19,16 +19,14 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe private readonly IProvideQueries _provideQueries; private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly ICapPublisher _capPublisher; - private readonly ITrackPullCacheService _trackPullCacheService; public TrackUpsertEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher, - IProvideQueries provideQueries, ITrackDetailsRepository trackDetailsRepository, ITrackPullCacheService trackPullCacheService) + IProvideQueries provideQueries, ITrackDetailsRepository trackDetailsRepository) { _orderRepository = orderRepository; _capPublisher = capPublisher; _provideQueries = provideQueries; _trackDetailsRepository = trackDetailsRepository; - _trackPullCacheService = trackPullCacheService; } [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] @@ -119,9 +117,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var trackContents = await _provideQueries.MatchTrackContentAsync(newOrderIds, @event.TrackCode); var insertTracks = new List(); - var triggerPullOrder = new List(); - - var providerDic=await GetProviderDic(orderIds); + foreach (var order in @event.OrderIdentifiers) { var track = tracks.FirstOrDefault(x => x.OrderId == order.OrderId); @@ -177,18 +173,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } canNextOrderIds.Add(order.OrderId); - - if(!providerDic.TryGetValue(order.OrderId,out var provider)) - continue; - - // todo:不要在upsert事件计算order的状态 - var config = - await _trackPullCacheService.GetPullParamWithContentConfigAsync(provider.SubSystemId, - provider.ServiceProviderId); - if (config!=null && config.ParamConfig!=null && config.ParamConfig.TrackContentCode == @event.TrackCode) - { - triggerPullOrder.Add(order.OrderId); - } } if (canNextOrderIds.Count == 0) return; @@ -210,7 +194,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe TrackPlace = @event.TrackPlace, TrackTime = @event.TrackTime, TrackTimeZone = @event.TrackTimeZone, - TriggerPullOrderIds = triggerPullOrder.ToArray() + TrackCode = @event.TrackCode }); // 触发轨迹推送事件(异步) @@ -232,17 +216,4 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe }; await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); } - - /// - /// 获取服务商字典 - /// - /// - /// - private async Task> GetProviderDic(int[] orderIds) - { - var providerList = await _provideQueries.FindOrderWithServiceProviderAsync(orderIds); - return providerList.GroupBy(val => val.OrderId) - .ToDictionary(val => val.Key, val => val.First()); - } - } \ No newline at end of file From f1d15c34df24b8709cddbdaddfa1130d67a9d87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Tue, 30 Jul 2024 16:47:47 +0800 Subject: [PATCH 53/60] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=8B=89?= =?UTF-8?q?=E5=8F=96=E7=95=8C=E9=9D=A2=E5=A2=9E=E5=8A=A0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=9A=E8=A7=A6=E5=8F=91=E6=8B=89=E5=8F=96=E8=8A=82=E7=82=B9?= =?UTF-8?q?=20=E4=BA=8C=E6=AC=A1=E8=87=AA=E6=B5=8B=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrackChangeAfterUpdateOrderEventHandler.cs | 6 +++--- .../Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 00925079..eef4d26a 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -53,11 +53,11 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa order.IsCompleted = @event.IsCompleted; } - if (providerDic.TryGetValue(order.Id, out var provider)) + if (!string.IsNullOrEmpty(@event.TrackCode) && providerDic.TryGetValue(order.Id, out var provider)) { var config = await _trackPullCacheService.GetPullParamWithContentConfigAsync(provider.SubSystemId, provider.ServiceProviderId); - if (config!=null && config.ParamConfig!=null && config.ParamConfig.TrackContentCode == @event.TrackCode) + if (!string.IsNullOrEmpty(config?.ParamConfig?.TrackContentCode) && config.ParamConfig.TrackContentCode!.ToLower() == @event.TrackCode.ToLower()) { // 触发拉取节点 order.IsTriggerPull = 1; @@ -75,7 +75,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa await _orderRepository.UpdateRangeAsync(updateOrders, x => new { x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, - x.LatestTrackTimeZone + x.LatestTrackTimeZone,x.IsTriggerPull }); // 预警计算 diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs index 4e016b17..4c6d7ed7 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs @@ -35,9 +35,4 @@ public class TrackPullConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "SubSystemId")] public int SubSystemId { get; set; } - - /// - /// 轨迹内容code - /// - public string? TrackContentCode { get; set; } } \ No newline at end of file From 6b43722fa6a40d9d1a547b1140865fe54f739973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Wed, 31 Jul 2024 10:21:27 +0800 Subject: [PATCH 54/60] =?UTF-8?q?feat:=20PullChangeBottomLineUpdateOrderEv?= =?UTF-8?q?ent=20=E4=BA=8B=E4=BB=B6=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrackPush/TrackPushContentConfigDto.cs | 1 - .../TrackStatus/GetTrackStatusDetailDto.cs | 5 ++++ .../PullChangeBottomLineUpdateOrderEvent.cs | 11 -------- .../TrackChangeAfterUpdateOrderEvent.cs | 5 ++++ .../Events/TrackUpsertEvent.cs | 5 ++++ .../AutoMapper/TrackPullAutoMapperProfile.cs | 1 + ...ChangeBottomLineUpdateOrderEventHandler.cs | 26 ----------------- ...TrackChangeAfterUpdateOrderEventHandler.cs | 8 +++++- .../EventHandlers/TrackRefreshEventHandler.cs | 28 +++++++++---------- .../EventHandlers/TrackUpsertEventHandler.cs | 3 +- .../ProvideServices/TrackPushService.cs | 24 ++-------------- .../TrackStatusAggregate/TrackStatusEntity.cs | 2 +- .../Consts/GlobalConst.MQ.cs | 5 ---- .../TrackStatus/GetTrackStatusDetailVO.cs | 5 ++++ .../Enums/DateTimeFormatEnum.cs | 5 ++++ .../Repositories/TrackStatusRepository.cs | 11 +++++--- 16 files changed, 59 insertions(+), 86 deletions(-) delete mode 100644 src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs delete mode 100644 src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs index f778ada8..8984a769 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs @@ -73,7 +73,6 @@ public class TrackPushContentConfigDto /// 扩展字段参数值 /// public string? ExpandFieldsValue { get; set; } - /// /// 时间格式枚举 diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs index fe39c418..b77a4a41 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs @@ -36,5 +36,10 @@ /// 轨迹内容英文 /// public string EntrackStatus { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs deleted file mode 100644 index ed59fce6..00000000 --- a/src/SJZY.Track.Application.Contract/Events/PullChangeBottomLineUpdateOrderEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace SJZY.Track.Application.Contract.Events; - -public class PullChangeBottomLineUpdateOrderEvent -{ - public List OrderIds { get; set; } = null!; - - /// - /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 - /// - public int DeficiencyTagValue { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs index 385b01f1..2eb42c61 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -56,4 +56,9 @@ public class TrackChangeAfterUpdateOrderEvent /// 轨迹内容代码 /// public string? TrackCode { get; set; } + + /// + /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + public int DeficiencyTagValue { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs index 621a441c..2884b824 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs @@ -53,4 +53,9 @@ public class TrackUpsertEvent public List Visited { get; set; } = new(); public TrackRefreshStruct TrackRefreshData { get; set; } + + /// + /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + public int DeficiencyTagValue { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs index c2409eea..8ca802aa 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs @@ -15,6 +15,7 @@ public class TrackPullAutoMapperProfile : Profile .ForMember(dest => dest.IsPush, opt => opt.MapFrom(source => false)); CreateMap(MemberList.None) .ForMember(dest => dest.TrackKeyword, opt => opt.MapFrom(src => string.Join(',', src.TrackKeywords))) + .ForMember(dest => dest.TrackZonePlaceValue, opt => opt.MapFrom(src => string.Join(',', src.TrackTimePlaceValue))) .ForMember(dest => dest.TrackKeywordReverse, opt => opt.MapFrom(src => string.Join(',', src.TrackKeywordReverses))); CreateMap(MemberList.None); CreateMap(MemberList.None); diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs deleted file mode 100644 index cccaf7eb..00000000 --- a/src/SJZY.Track.Application/CAP/EventHandlers/PullChangeBottomLineUpdateOrderEventHandler.cs +++ /dev/null @@ -1,26 +0,0 @@ -using DotNetCore.CAP; -using SJZY.Track.Application.Contract.Events; -using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Consts; -using Volo.Abp.DependencyInjection; - -namespace SJZY.Track.Application.CAP.EventHandlers; - -/// -/// 拉去轨迹后,执行了兜底操作还是失败的标记操作 -/// -public class PullChangeBottomLineUpdateOrderEventHandler :ITransientDependency, ICapSubscribe -{ - private readonly IOrderRepository _orderRepository; - - public PullChangeBottomLineUpdateOrderEventHandler(IOrderRepository orderRepository) - { - _orderRepository = orderRepository; - } - - [CapSubscribe(GlobalConst.PullChangeBottomLineUpdateOrderSubscribe)] - public async Task ConsumerAsync(PullChangeBottomLineUpdateOrderEvent @event) - { - var rows =await _orderRepository.UpdateBatchIdsAsync(@event.OrderIds, @event.DeficiencyTagValue); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index eef4d26a..2d9540aa 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -48,6 +48,12 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa } } + // 执行轨迹兜底时 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + if (@event.DeficiencyTagValue > 0 && @event.DeficiencyTagValue<=3) + { + order.DeficiencyTag = @event.DeficiencyTagValue; + } + if (!order.IsCompleted) { order.IsCompleted = @event.IsCompleted; @@ -75,7 +81,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa await _orderRepository.UpdateRangeAsync(updateOrders, x => new { x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, - x.LatestTrackTimeZone,x.IsTriggerPull + x.LatestTrackTimeZone,x.IsTriggerPull,x.DeficiencyTag }); // 预警计算 diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs index 8afe8e0c..8411bf76 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs @@ -225,6 +225,16 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe return; } + int deficiencyTagValue = 0; + // 触发了兜底,但是没有兜底住,对订单进行标记 + if (hasPlaceBottomLine || hasTimezoneBottomLine) + { + //1表示时区,2表示发生地,3表示两种 + var placeTagValue = hasPlaceBottomLine ? 2 : 0; + var timezoneTagValue = hasTimezoneBottomLine ? 1 : 0; + deficiencyTagValue = placeTagValue + timezoneTagValue; + } + // 新增/更新轨迹 var trackUpsertEvent = new TrackUpsertEvent { @@ -237,6 +247,7 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe OrderType = context.OrderType, } }, + TrackRefreshData = new TrackRefreshStruct { ServiceProviderName = context.ServiceProviderName, @@ -250,26 +261,13 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe TrackCode = matchedContentConfig.TrackContentCode, TrackPlace = trackPlace ?? GlobalConst.EmptyString, TrackTime = trackTime ?? DateTime.Now, - TrackTimeZone = trackTimeZone ?? 8 + TrackTimeZone = trackTimeZone ?? 8, + DeficiencyTagValue = deficiencyTagValue }; trackUpsertEvent.IsAdd = !await _trackDetailsRepository.AnyByCodeAsync(context.OrderId, matchedContentConfig.TrackContentCode); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent); - - // 触发了兜底,但是没有兜底住,对订单进行标记 - if (hasPlaceBottomLine || hasTimezoneBottomLine) - { - //1表示时区,2表示发生地,3表示两种 - var placeTagValue = hasPlaceBottomLine ? 2 : 0; - var timezoneTagValue = hasTimezoneBottomLine ? 1 : 0; - PullChangeBottomLineUpdateOrderEvent deficiencyTagEvent = new PullChangeBottomLineUpdateOrderEvent - { - OrderIds = new List(){context.OrderId}, - DeficiencyTagValue = placeTagValue+timezoneTagValue - }; - await _capPublisher.PublishAsync(GlobalConst.PullChangeBottomLineUpdateOrderSubscribe, deficiencyTagEvent); - } } /// diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index 5e73128b..703900c5 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -194,7 +194,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe TrackPlace = @event.TrackPlace, TrackTime = @event.TrackTime, TrackTimeZone = @event.TrackTimeZone, - TrackCode = @event.TrackCode + TrackCode = @event.TrackCode, + DeficiencyTagValue = @event.DeficiencyTagValue }); // 触发轨迹推送事件(异步) diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs index c7663f86..3ad8cc46 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs @@ -22,17 +22,17 @@ public class TrackPushService : ApplicationService private readonly ICapPublisher _capPublisher; private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; private readonly IHttpClientProxy _requestCurrentUserService; - TrackPushEventHandler _trackPushEventHandler; + public TrackPushService(IOrderRepository orderRepository , ICapPublisher capPublisher , ITrackPushRecordsRepository trackPushRecordsRepository, - IHttpClientProxy requestCurrentUserService, TrackPushEventHandler trackPushEventHandler) + IHttpClientProxy requestCurrentUserService) { _orderRepository = orderRepository; _capPublisher = capPublisher; _trackPushRecordsRepository = trackPushRecordsRepository; _requestCurrentUserService = requestCurrentUserService; - _trackPushEventHandler = trackPushEventHandler; + } /// @@ -43,24 +43,6 @@ public class TrackPushService : ApplicationService [HttpPost("Track/Push")] public async Task PushTrackAsync(PushTrackInput input) { - var trackPushEvenst = new TrackPushEvent -{ - OptionType = OptionType.新增, // Assuming OptionType.新增 corresponds to 1 - SubSystemId = 9534, - CustomId = 228618, - OrderIds = new int[] { 1 }, - TrackCode = "CP", - OperationMan = "郑志红", - SystemPushInfo = new SystemPushStruct - { - TrackStatus = null, - TrackContent = null, - TrackPlace = null, - TrackTime = DateTime.Parse("0001-01-01T00:00:00"), - TrackTimeZone = 0.0f - } -}; - await _trackPushEventHandler.ConsumerAsync(trackPushEvenst); input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 var orders = await _orderRepository.GetArrayAsync(x => diff --git a/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs index dd98a21d..0b200c1c 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs @@ -25,7 +25,7 @@ public class TrackStatusEntity : IFullAuditedBasicEntitys, IAggregateRoot public string EnStatus { get; set; } = null!; /// - /// 所属节点(主数据枚举ServiceNode) + /// 所属节点(来自表 t_track_node) 之前是枚举,后续调整为表 /// [SugarColumn(ColumnName = "Node")] public int Node { get; set; } diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs index 1b853ffe..378f0b89 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs @@ -56,9 +56,4 @@ public partial class GlobalConst /// 关联订单后补轨迹 /// public const string OrderLinkAfterFillTrack = "SJZY.Track.OrderLinkAfterFillTrack"; - - /// - /// 拉取轨迹触发兜底后更新订单 - /// - public const string PullChangeBottomLineUpdateOrderSubscribe = "SJZY.Track.PullChangeBottomLineUpdateOrder"; } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs index 66de23a9..76c4ac32 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs @@ -36,4 +36,9 @@ public class GetTrackStatusDetailVO /// 轨迹内容英文 /// public string EntrackStatus { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs b/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs index 37e3c4fc..f7d68b5e 100644 --- a/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs +++ b/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs @@ -5,6 +5,11 @@ namespace SJZY.Track.Domain.Enums; /// public enum DateTimeFormatEnum { + /// + /// 默认 + /// + None = 0, + /// /// 时间戳 /// diff --git a/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs index a4abd5b5..7ea0fb26 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs @@ -1,3 +1,4 @@ +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.TrackStatus; using SJZY.Track.Domain.VEntities; @@ -14,9 +15,10 @@ public class TrackStatusRepository : BasicRepository, ITrackS public async Task GetDetailAsync(int id) { var detail = await Context.Queryable() - .LeftJoin((a, b) => a.SubSystemId == b.Id&&b.IsDeleted==false) - .Where((a, b) => a.Id == id) - .Select((a, b) => new GetTrackStatusDetailVO + .InnerJoin((a,t)=>a.Node==t.Id) + .LeftJoin((a, t,b) => a.SubSystemId == b.Id&&b.IsDeleted==false) + .Where((a,t, b) => a.Id == id) + .Select((a, t,b) => new GetTrackStatusDetailVO { Id = a.Id, SubSystemId = a.SubSystemId, @@ -24,7 +26,8 @@ public class TrackStatusRepository : BasicRepository, ITrackS Code = a.Code, EntrackStatus = a.EnStatus, NodeId = a.Node, - TrackStatus = a.Status + TrackStatus = a.Status, + NodeName = t.NodeName }) .FirstAsync(); return detail; From 010408985ec5325fedafea3a550557797010d26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Wed, 31 Jul 2024 16:34:29 +0800 Subject: [PATCH 55/60] =?UTF-8?q?feat:=20=E8=A7=A3=E5=86=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3Track/PushWarnForTask=E7=9A=84=E9=94=81=E9=95=BF?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=8D=A0=E9=A2=86=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProvideServices/TrackPushService.cs | 18 +++++++++++++++--- .../OrderAggregate/IOrderRepository.cs | 2 +- .../Repositories/OrderRepository.cs | 6 +++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs index 3ad8cc46..c9a53360 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs @@ -92,9 +92,21 @@ public class TrackPushService : ApplicationService [HttpPost("Track/PushWarnForTask")] public async Task PushWarnForTaskAsync() { - // todo:订单数据上来后一次性update是否会引发长时间X独占? - var count = await _orderRepository.PushWarnOrdersAsync(); - return $"本次预警扫描了:{count}个订单"; + int total = 0, pageSize = 1000,waitTime = 1000; + var dateTimes = Enumerable.Range(1, 12).Select(val => DateTime.Now.AddHours(-val)).ToList(); + + foreach (var dateTime in dateTimes) + { + var rows = 0; + do + { + rows = await _orderRepository.PushWarnOrdersAsync(pageSize,dateTime); + total+=rows; + await Task.Delay(waitTime); + }while (rows!= pageSize); + } + + return $"本次预警扫描了:{total}个订单"; } /// diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs index ff7ab6f7..746cf6b5 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs @@ -29,7 +29,7 @@ public interface IOrderRepository : IBasicRepository /// 更新推送预警单 /// /// - Task PushWarnOrdersAsync(); + Task PushWarnOrdersAsync(int pageSize,DateTime createTime); /// /// 更新缺失标记,时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index 6f2130ae..ff1fdfdf 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -61,7 +61,7 @@ public class OrderRepository : BasicRepository, IOrderRepository, I tran.Complete(); } - public async Task PushWarnOrdersAsync() + public async Task PushWarnOrdersAsync(int pageSize, DateTime createTime) { return await Context.Ado.ExecuteCommandAsync(@"UPDATE `t_track_push_config` `a` LEFT JOIN `t_order` `b` ON `a`.`SubSystemId` = `b`.`SubSystemId` AND `a`.`CustomId` = `b`.`CustomId` @@ -69,8 +69,8 @@ SET `b`.`QuestionType` = CASE WHEN `b`.`LatestPushTime` IS NULL THEN 2 WHEN `b`.`LatestPushTime` < DATE_SUB(NOW(), INTERVAL 12 HOUR) THEN 2 ELSE 0 END -WHERE `b`.`IsCompleted` = 0 AND `b`.`QuestionType` != 1 AND `b`.`CreateTime` < DATE_SUB(NOW(), INTERVAL 12 HOUR) -AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;"); +WHERE `b`.`IsCompleted` = 0 AND `b`.`QuestionType` != 1 AND `b`.`CreateTime` < @createTime +AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0 limit @pageSize", new { pageSize,createTime }); } #region 订单关联 From 8f8d7b2a44068ab5aef7137a884cdaa340016239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Wed, 31 Jul 2024 18:07:10 +0800 Subject: [PATCH 56/60] =?UTF-8?q?feat:=20=E7=BC=93=E5=AD=98=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/Forewarning/ClearRulCacheEvent.cs | 9 + .../Services/IForewarningCacheService.cs | 12 +- .../HostServices/RedisHostService.cs | 10 +- .../ForewarningCacheService.cs | 178 ++++++++++-------- .../ForewarningServices/KpiAreaService.cs | 13 +- .../IWarningRepository.cs | 9 +- .../KPIAreaAggregate/IKpiAreaRepository.cs | 2 +- .../Dtos/Forewarning/RuleAreaBaseInfo.cs | 3 + .../Repositories/KpiAreaRepository.cs | 18 +- .../Repositories/WarningRepository.cs | 14 +- 10 files changed, 163 insertions(+), 105 deletions(-) create mode 100644 src/SJZY.Track.Application.Contract/Dtos/Forewarning/ClearRulCacheEvent.cs create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfo.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ClearRulCacheEvent.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ClearRulCacheEvent.cs new file mode 100644 index 00000000..e875e4b8 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ClearRulCacheEvent.cs @@ -0,0 +1,9 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + + +public class ClearRulCacheEvent +{ + public List Items { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs index d7743c32..08d8fafb 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs @@ -24,11 +24,19 @@ public interface IForewarningCacheService /// 重置本地缓存 /// /// - Task Clear(); + Task Clear(ClearRulCacheEvent @event); /// /// 清除redis 缓存 /// /// - Task ClearRedis(); + Task ClearRedisByAreaId(int areaId); + + /// + /// 清除redis 缓存 + /// + /// 子系统id + /// 客户id + /// + Task ClearRedisBySystemIdAndCustomer(int subSystemId, int customerId); } \ No newline at end of file diff --git a/src/SJZY.Track.Application/HostServices/RedisHostService.cs b/src/SJZY.Track.Application/HostServices/RedisHostService.cs index 702afb51..0a7237e8 100644 --- a/src/SJZY.Track.Application/HostServices/RedisHostService.cs +++ b/src/SJZY.Track.Application/HostServices/RedisHostService.cs @@ -1,8 +1,11 @@ using Microsoft.Extensions.Hosting; using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.UserCenter.SharedModel.Dtos.PHP.User; namespace SJZY.Track.Application.HostServices; @@ -15,7 +18,7 @@ public class RedisHostService:IHostedService _forewarningCacheService = forewarningCacheService; } - public Task StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) { // 订阅频道 RedisHelper.Client.Subscribe(GetKey(), Subscribe); @@ -34,9 +37,10 @@ public class RedisHostService:IHostedService { // 暂时只处理一个事件,不做反序列化 //var instance = Newtonsoft.Json.JsonConvert.DeserializeObject(value as string); + var instance = Newtonsoft.Json.JsonConvert.DeserializeObject(value as string); + if(instance!=null) + _forewarningCacheService.Clear(instance); } - - _forewarningCacheService.Clear(); } private string GetKey() diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs index a79684d6..effa72e3 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using FreeRedis; using SJZY.Expand.ABP.Core; using SJZY.Expand.ABP.Core.PublicMethords; @@ -11,46 +12,36 @@ using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; -public class ForewarningCacheService: IForewarningCacheService, ISingletonDependency +public class ForewarningCacheService : IForewarningCacheService, ISingletonDependency { readonly IKpiAreaRepository _kpiAreaRepository; readonly IWarningRepository _warningRepository; - const string GlobalKpiAreaLockKey = "KKpiAreaLockKey_GlobalLock"; private const string GlobalWaningLockKey = "GlobalWaningLockKey_GlobalLock"; - - private Dictionary> _rules = new(); - private Dictionary>? _areas = new(); - readonly object _lock = new object(); + private readonly ConcurrentDictionary> _rules = new(); + private readonly ConcurrentDictionary> _areas = new(); + object _lock = new object(); public ForewarningCacheService(IKpiAreaRepository kpiAreaRepository, IWarningRepository warningRepository) { _kpiAreaRepository = kpiAreaRepository; _warningRepository = warningRepository; } - - - string WarningKey(int subSystemId, int customerId) => $"{GlobalConst.TrackWarningKeyPrefix}:{subSystemId}:{customerId}"; - string WarningKey() => $"{GlobalConst.TrackWarningKeyPrefix}:all"; + string WarningKey(int subSystemId, int customerId) => + $"{GlobalConst.TrackWarningKeyPrefix}:{subSystemId}:{customerId}"; - string AreaKey() - { - return $"{GlobalConst.TrackAreaKeyPrefix}"; - } + string AreaKey(int areaId) => $"{GlobalConst.TrackAreaKeyPrefix}:{areaId}"; - // 30w => 1w => local public async Task?> GetRulesAsync(int subSystemId, int customerId) { var key = WarningKey(subSystemId, customerId); - var rules = _rules.GetValueOrDefault(key); - - if (rules == null) - { - return await GetRules(subSystemId, customerId); - } - - return rules; + if( _rules.TryGetValue(key,out var rules)) + { + return rules; + } + + return await GetRules(subSystemId, customerId); } private List WriteRules(List rules) @@ -63,7 +54,7 @@ public class ForewarningCacheService: IForewarningCacheService, ISingletonDepend { areaList = GetAreaInfoByAreaId(item.AreaId!.Value); } - + var entry = new ForewarningRuleCacheEntry { Id = item.Id, @@ -74,13 +65,15 @@ public class ForewarningCacheService: IForewarningCacheService, ISingletonDepend StartTrackStatusId = item.StartTrackStatusId, EndTrackStatusId = item.EndTrackStatusId, CargoType = item.CargoType, - Months = string.IsNullOrEmpty(item.Months)?new List():item.Months.Split('/').Select(int.Parse).ToList(), + Months = string.IsNullOrEmpty(item.Months) + ? new List() + : item.Months.Split('/').Select(int.Parse).ToList(), IsTransit = item.IsTransit, Areas = areaList, ProductCode = item.ProductCode, LeavePort = item.LeavePort }; - + result.Add(entry); } @@ -89,64 +82,60 @@ public class ForewarningCacheService: IForewarningCacheService, ISingletonDepend private async Task?> GetRules(int systemId, int customerId) { - var key = WarningKey(); + var key = WarningKey(systemId, customerId); var result = RedisHelper.Client.Get>(key); if (result != null) { // 非线程安全,需要加锁 lock (_lock) { - _rules = result.GroupBy(val => WarningKey(val.SystemId, val.CustomerId)) - .ToDictionary(val => val.Key, val => WriteRules(val.ToList())); + if (_rules.TryGetValue(key, out var ruleResult)) + { + return ruleResult; + } - return _rules.GetValueOrDefault(WarningKey(systemId,customerId)); + ruleResult = WriteRules(result); + _rules.TryAdd(key,ruleResult); + return ruleResult; } } - + // 非线程安全,需要加锁 using (RedisHelper.Client.Lock(GlobalWaningLockKey, 20)) { - var ruleResult = _rules.GetValueOrDefault(WarningKey(systemId,customerId)); - if (ruleResult == null) - { - var warnings = await _warningRepository.GetAllWarningRule(); - if (warnings == null || warnings.Count == 0) - { - RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); - return new List(); - } - - RedisHelper.Client.Set(key, warnings); - _rules = warnings.GroupBy(val => WarningKey(val.SystemId, val.CustomerId)) - .ToDictionary(val => val.Key, val => WriteRules(val.ToList())); + if (_rules.TryGetValue(key, out var ruleResult)) return ruleResult; - return _rules.GetValueOrDefault(WarningKey(systemId,customerId)); + var warnings = await _warningRepository.GetWarningRule(systemId, customerId); + if (warnings == null || warnings.Count == 0) + { + RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); + return new List(); } + RedisHelper.Client.Set(key, warnings); + ruleResult = WriteRules(warnings); + _rules.TryAdd(key, ruleResult); return ruleResult; } - } - - // a b c del local cusomer 3 del redis cache pub del redis cache + public Task DeleteRulesAsync(int subSystemId, int customerId) { - _rules.Remove(WarningKey(subSystemId, customerId)); + _rules.Remove(WarningKey(subSystemId, customerId),out _); return Task.CompletedTask; } private List? GetAreaInfoByAreaId(int areaId) { - if (_areas == null || _areas.Count == 0) - { - var areas = GetAreas(); - if(areas==null || areas.Count==0) return null; - _areas = areas.GroupBy(x => x.AreaId) - .ToDictionary(x => x.Key, x => x.Select(KpiAreaInfoToEntry).ToList()); - } + if (_areas.TryGetValue(areaId, out var areaInfos)) return areaInfos; + + var areas = GetAreas(areaId); + if (areas == null || areas.Count == 0) return null; - return _areas.GetValueOrDefault(areaId); + areaInfos = areas.Select(KpiAreaInfoToEntry).ToList(); + _areas.TryAdd(areaId, areaInfos); + return areaInfos; } AreaCacheEntry KpiAreaInfoToEntry(KpiAreaInfo model) @@ -162,47 +151,74 @@ public class ForewarningCacheService: IForewarningCacheService, ISingletonDepend } /// - /// 获取所有区域 + /// 获取区域 /// /// - private List? GetAreas() + private List? GetAreas(int areaId) { - var key = AreaKey(); + var key = AreaKey(areaId); var result = RedisHelper.Client.Get>(key); if (result == null) { - using (RedisHelper.Client.Lock(GlobalKpiAreaLockKey, 20)) + result = RedisHelper.Client.Get>(key); + if (result != null) return new List(); + + var kpiArea = _kpiAreaRepository.GetAreaInfosByAreaId(areaId); + if (kpiArea == null) { - result = RedisHelper.Client.Get>(key); - if (result != null) return new List(); - - var kpiArea = _kpiAreaRepository.GetAllAreaInfos(); - if (kpiArea == null) - { - RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); - return new List(); - } - - RedisHelper.Client.Set(key, kpiArea); - return kpiArea; + RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); + return new List(); } + + RedisHelper.Client.Set(key, kpiArea); + return kpiArea; } return result; } - - public Task Clear() + + public Task Clear(ClearRulCacheEvent @event) { - _rules?.Clear(); - _areas?.Clear(); + foreach (var item in @event.Items) + { + DeleteRulesAsync(item.SystemId, item.CustomerId); + } return Task.CompletedTask; } - public Task ClearRedis() + public async Task ClearRedisBySystemIdAndCustomer(int subSystemId,int customerId) { - RedisHelper.Client.Del(WarningKey()); - RedisHelper.Client.Del(AreaKey()); - return Task.CompletedTask; + await RedisHelper.Client.DelAsync(WarningKey(subSystemId, customerId)); + var eventModel = new ClearRulCacheEvent + { + Items = new List() + { + new RuleAreaBaseInfo(subSystemId, customerId) + } + }; + + await PublishEvent(eventModel); } + public async Task ClearRedisByAreaId(int areaId) + { + var baseInfos = await _warningRepository.GetWarningRuleByAreaId(areaId); + if(baseInfos==null||baseInfos.Count==0) return; + baseInfos = baseInfos.DistinctBy(val => WarningKey(val.SystemId, val.CustomerId)).ToList(); + + var willDelKeys = baseInfos.Select(val => WarningKey(val.SystemId, val.CustomerId)).ToArray(); + await RedisHelper.Client.DelAsync(willDelKeys); + await RedisHelper.Client.DelAsync(AreaKey(areaId)); + var eventModel = new ClearRulCacheEvent + { + Items = baseInfos + }; + + await PublishEvent(eventModel); + } + + private async Task PublishEvent(ClearRulCacheEvent @event) + { + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, @event.ToJson()); + } } \ No newline at end of file diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs index 3b693a1c..354e177d 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -42,8 +42,7 @@ public class KpiAreaService : ApplicationService { var ruleAreaEntity = ObjectMapper.Map(input); var ruleInfoId = await _ruleAreaRepository.AddAreaInfoAsync(ruleAreaEntity); - await _forewarningCacheService.ClearRedis(); - await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); + await _forewarningCacheService.ClearRedisByAreaId(input.AreaId); return new UnifyResultDto(true, ruleInfoId, "添加成功"); } @@ -56,8 +55,7 @@ public class KpiAreaService : ApplicationService public async ValueTask DeleteKpiArea(int id) { await _ruleAreaRepository.DeleteArea(id); - await _forewarningCacheService.ClearRedis(); - await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); + await _forewarningCacheService.ClearRedisByAreaId(id); return new UnifyResultDto(true, "删除成功"); } @@ -69,9 +67,10 @@ public class KpiAreaService : ApplicationService [HttpDelete("KpiArea/DeleteKpiAreaInfo")] public async ValueTask DeleteKpiAreaInfo(int id) { + var info=await _ruleAreaRepository.GetAreaInfoById(id); + if (info == null) return new UnifyResultDto(false,"未找到该区域信息"); await _ruleAreaRepository.DeleteAreaInfo(id); - await _forewarningCacheService.ClearRedis(); - await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); + await _forewarningCacheService.ClearRedisByAreaId(info.AreaId); return new UnifyResultDto(true, "删除成功"); } @@ -113,7 +112,7 @@ public class KpiAreaService : ApplicationService var ruleAreaEntity = ObjectMapper.Map(input, areaInfo); await _ruleAreaRepository.UpdateAreaInfoAsync(ruleAreaEntity); - await _forewarningCacheService.ClearRedis(); + await _forewarningCacheService.ClearRedisByAreaId(areaInfo.AreaId); await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, "clear local cache"); return new UnifyResultDto(true, "更新成功"); } diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs index a864c05a..e06ea6ae 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs @@ -64,6 +64,13 @@ public interface IWarningRepository : IBasicRepository /// 获取预警规则列表 /// /// - Task?> GetAllWarningRule(); + Task?> GetWarningRule(int systemId, int customerId); + + /// + /// 获取预警规则基础信息 + /// + /// + /// + Task?> GetWarningRuleByAreaId(int areaId); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs index 21d15342..3b3a00b0 100644 --- a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs @@ -64,5 +64,5 @@ public interface IKpiAreaRepository : IBasicRepository /// 获取所有区域信息 /// /// - List? GetAllAreaInfos(); + List? GetAreaInfosByAreaId(int areaId); } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfo.cs new file mode 100644 index 00000000..a8fef8d3 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfo.cs @@ -0,0 +1,3 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public record RuleAreaBaseInfo(int SystemId, int CustomerId); \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs index e2008c27..3eb4a25d 100644 --- a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -94,17 +94,19 @@ public class KpiAreaRepository : BasicRepository, IKpiAreaReposi /// 获取所有区域信息 /// /// - public List GetAllAreaInfos() + public List GetAreaInfosByAreaId(int areaId) { return Context.Queryable() - .Select((x)=>new KpiAreaInfo + .InnerJoin((r,i)=>r.AreaId==i.Id) + .Where((r,i)=>r.AreaId==areaId) + .Select((r,i)=>new KpiAreaInfo { - AreaId = x.AreaId, - Country = x.CountryCode, - LeftPostcode = x.LeftPostcode, - City = x.City, - Province = x.Province, - RightPostcode = x.RightPostcode + AreaId = r.AreaId, + Country = r.CountryCode, + LeftPostcode = r.LeftPostcode, + City = r.City, + Province = r.Province, + RightPostcode = r.RightPostcode }) .ToList(); } diff --git a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs index 23286a59..61463fe0 100644 --- a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs @@ -110,11 +110,11 @@ public class WarningRepository : BasicRepository, IWarningReposit return warning; } - public Task?> GetAllWarningRule() + public Task?> GetWarningRule(int systemId, int customerId) { return Context.Queryable() .InnerJoin((a, b) => a.WarningId == b.Id) - .Where((a,b)=>b.IsEnable) + .Where((a,b)=>b.IsEnable && b.SubSystemId == systemId && b.CustomerId == customerId) .Select((a,b)=>new WarningRuleCacheDto { Id = a.Id, @@ -135,4 +135,14 @@ public class WarningRepository : BasicRepository, IWarningReposit }) .ToListAsync(); } + + public Task?> GetWarningRuleByAreaId(int areaId) + { + return Context.Queryable() + .InnerJoin((a, b) => a.WarningId == b.Id) + .Where((a,b)=>b.IsEnable && a.AreaId==areaId) + .Select((a,b)=>new RuleAreaBaseInfo(b.CustomerId,b.SubSystemId)) + .ToListAsync(); + } + } \ No newline at end of file From ca68cde257cbdcdbcd7d865016af8057c72a91ea Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Wed, 31 Jul 2024 18:21:23 +0800 Subject: [PATCH 57/60] temp --- .../Forewarning/WarningNotifyCacheEntry.cs | 18 ++--- .../Dtos/Forewarning/WarningOrderDto.cs | 5 ++ .../Services/IForewarningNotifyService.cs | 3 +- ...TrackChangeAfterUpdateOrderEventHandler.cs | 1 + .../Helpers/ForewarningHelper.cs | 2 + .../ForewarningCacheService.cs | 15 ++-- .../ForewarningNotifyService.cs | 68 +++++++++--------- .../ForewarningServices/ForewarningService.cs | 25 +++++-- .../IWarningRepository.cs | 14 ---- .../ForewarningAggregate/WarningRuleEntity.cs | 16 ++++- .../Consts/GlobalConst.Redis.cs | 5 ++ .../Dtos/Forewarning/GetWarningNotifiesVo.cs | 69 +++++++++++++++++++ .../Queries/IWarningQueries.cs | 27 ++++++++ .../Queries/WarningQueries.cs | 66 ++++++++++++++++++ .../Repositories/WarningRepository.cs | 36 ---------- .../SJZY.Track.Repository.csproj | 12 ++++ .../Entitys/TrackPushRecordEntity.cs | 59 ---------------- .../Services/ITrackPushRecordRepository.cs | 8 --- .../Services/TrackPushRecordRepository.cs | 10 --- .../Entitys/TrackPushRecordDetailsEntity.cs | 47 ------------- .../ITrackPushRecordDetailsRepository.cs | 8 --- .../TrackPushRecordDetailsRepository.cs | 10 --- 22 files changed, 271 insertions(+), 253 deletions(-) create mode 100644 src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs create mode 100644 src/SJZY.Track.Domain/Queries/IWarningQueries.cs create mode 100644 src/SJZY.Track.Repository/Queries/WarningQueries.cs delete mode 100644 src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs delete mode 100644 src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs delete mode 100644 src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs delete mode 100644 src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs delete mode 100644 src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs delete mode 100644 src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs index 71112bb8..61913c6d 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs @@ -2,17 +2,17 @@ namespace SJZY.Track.Application.Contract.Dtos.Forewarning; public class WarningNotifyCacheEntry { - /// - /// 订单id - /// - public int OrderId { get; set; } - /// /// 规则id /// public int RuleId { get; set; } + + /// + /// 订单id + /// + public int OrderId { get; set; } - public WarningNotifyCacheEntry(int orderId, int ruleId) + public WarningNotifyCacheEntry(int ruleId, int orderId) { RuleId = ruleId; OrderId = orderId; @@ -21,12 +21,12 @@ public class WarningNotifyCacheEntry public WarningNotifyCacheEntry(string notifyValue) { var values = notifyValue.Split(':'); - OrderId = int.Parse(values[0]); - RuleId = int.Parse(values[1]); + RuleId = int.Parse(values[0]); + OrderId = int.Parse(values[1]); } public override string ToString() { - return $"{OrderId}:{RuleId}"; + return $"{RuleId}:{OrderId}"; } } \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs index c9a395b9..035175cc 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs @@ -7,6 +7,11 @@ public class WarningOrderDto /// public int Id { get; set; } + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } + public string? CargoType { get; set; } public int Month { get; set; } diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs index 2709a84c..914535ae 100644 --- a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs @@ -19,6 +19,5 @@ public interface IForewarningNotifyService /// /// 发送通知。 /// - /// 通知间隔时间,以分钟为单位。 - void SendNotification(int intervalMinute); + Task SendNotificationAsync(); } \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 2d9540aa..9c642169 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -125,6 +125,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa Orders = orders.Select(order => new WarningOrderDto { Id = order.Id, + TrackTime = @event.TrackTime, CargoType = order.CargoType, Month = order.CreateTime.Month, diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index eb79d6f0..50ea1424 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -60,7 +60,9 @@ public class ForewarningHelper for (var i = 0; i < repeat; i++, row++) { rules[row].StartTrackStatusId = span.StartTrackStatusId; + rules[row].StartTrackStatus = span.StartTrackStatus; rules[row].EndTrackStatusId = span.EndTrackStatusId; + rules[row].EndTrackStatus = span.EndTrackStatus; } } } diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs index effa72e3..7c3b3b00 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -1,13 +1,12 @@ using System.Collections.Concurrent; -using FreeRedis; using SJZY.Expand.ABP.Core; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Services; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -15,17 +14,17 @@ namespace SJZY.Track.Application.Services.ForewarningServices; public class ForewarningCacheService : IForewarningCacheService, ISingletonDependency { readonly IKpiAreaRepository _kpiAreaRepository; - readonly IWarningRepository _warningRepository; - + private readonly IWarningQueries _warningQueries; + private const string GlobalWaningLockKey = "GlobalWaningLockKey_GlobalLock"; private readonly ConcurrentDictionary> _rules = new(); private readonly ConcurrentDictionary> _areas = new(); object _lock = new object(); - public ForewarningCacheService(IKpiAreaRepository kpiAreaRepository, IWarningRepository warningRepository) + public ForewarningCacheService(IKpiAreaRepository kpiAreaRepository, IWarningQueries warningQueries) { _kpiAreaRepository = kpiAreaRepository; - _warningRepository = warningRepository; + _warningQueries = warningQueries; } string WarningKey(int subSystemId, int customerId) => @@ -105,7 +104,7 @@ public class ForewarningCacheService : IForewarningCacheService, ISingletonDepen { if (_rules.TryGetValue(key, out var ruleResult)) return ruleResult; - var warnings = await _warningRepository.GetWarningRule(systemId, customerId); + var warnings = await _warningQueries.GetWarningRule(systemId, customerId); if (warnings == null || warnings.Count == 0) { RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); @@ -202,7 +201,7 @@ public class ForewarningCacheService : IForewarningCacheService, ISingletonDepen public async Task ClearRedisByAreaId(int areaId) { - var baseInfos = await _warningRepository.GetWarningRuleByAreaId(areaId); + var baseInfos = await _warningQueries.GetWarningRuleByAreaId(areaId); if(baseInfos==null||baseInfos.Count==0) return; baseInfos = baseInfos.DistinctBy(val => WarningKey(val.SystemId, val.CustomerId)).ToList(); diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index 003d6cf6..ea453aca 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -2,7 +2,9 @@ using FreeRedis; using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.ForewarningServices; @@ -12,11 +14,13 @@ namespace SJZY.Track.Application.Services.ForewarningServices; /// public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency { - private readonly ForewarningCacheService _cacheService; + private readonly IForewarningCacheService _cacheService; + private readonly IWarningQueries _warningQueries; - public ForewarningNotifyService(ForewarningCacheService cacheService) + public ForewarningNotifyService(IForewarningCacheService cacheService, IWarningQueries warningQueries) { _cacheService = cacheService; + _warningQueries = warningQueries; } /// @@ -31,8 +35,8 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep var rules = await _cacheService.GetRulesAsync(dto.SubSystemId, dto.CustomerId); if (rules == null || rules.Count == 0) return; - var zMembers = new List(); - var members = new List(); + var adds = new List<(int ruleId, int orderId, int cnt, long ts)>(); + var dels = new List<(int ruleId, int orderId)>(); foreach (var order in dto.Orders) { MatchRule( @@ -40,33 +44,28 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep order ).ForEach(rule => { - var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(rule.WarnTimeSpan)); - var entry = new WarningNotifyCacheEntry(rule.Id, order.Id); - var notifyValue = new ZMember(entry.ToString(), notifyTimestamp); - zMembers.Add(notifyValue); + var timestamp = GetTimestamp(order.TrackTime.AddMinutes(rule.WarnTimeSpan)); + adds.Add((rule.Id, order.Id, rule.WarnCount, timestamp)); }); - var endingRules = MatchRule( + MatchRule( rules.Where(rule => rule.EndTrackStatusId == dto.TrackStatusId).ToList(), order - ); - - foreach (var member in endingRules.Select(rule => - new WarningNotifyCacheEntry(rule.Id, order.Id).ToString()) - ) - { - // todo: pipeline optimize? - var score = await RedisHelper.Client.ZScoreAsync(GlobalConst.ForewarningNotifyKey, member); - // tips: score is null 说明发生ending时,没有匹配到规则,所以没有add到set,不需要删除 - if (score != null && (long)score > GetTimestamp(DateTime.Now)) - { - members.Add(member); - } - } + ).ForEach(rule => { dels.Add((rule.Id, order.Id)); }); } - await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKey, zMembers.ToArray()); - await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKey, members.ToArray()); + + await RedisHelper.Client.HSetAsync(GlobalConst.ForewarningNotifyCntKey, + adds.ToDictionary(x => $"{x.ruleId}_{x.orderId}", x => x.cnt)); + await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKey, adds.Select(x => + { + var entry = new WarningNotifyCacheEntry(x.ruleId, x.orderId); + return new ZMember(entry.ToString(), x.ts); + }).ToArray()); + await RedisHelper.Client.HDelAsync(GlobalConst.ForewarningNotifyCntKey, + dels.Select(x => $"{x.ruleId}_{x.orderId}").ToArray()); + // await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKey, + // dels.Select(x => $"{x.ruleId}:{x.orderId}").ToArray()); } private static List MatchRule(List rules, @@ -118,17 +117,20 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep return res; } - public void SendNotification(int intervalMinute) + public async Task SendNotificationAsync() { - var currentTimestamp = GetTimestamp(DateTime.Now); - var notifyMembers = - RedisHelper.Client.ZRangeByScore(GlobalConst.ForewarningNotifyKey, 0, currentTimestamp); - if (notifyMembers == null || notifyMembers.Length == 0) - return; + var max = GetTimestamp(DateTime.Now); + var set = await RedisHelper.Client.ZRangeByScoreAsync(GlobalConst.ForewarningNotifyKey, 0, max); + + if (set.IsNullOrEmpty()) return; - var notifyValues = notifyMembers.Select(val => new WarningNotifyCacheEntry(val)); - foreach (var notifyValue in notifyValues) + var entries = set.Select(x => new WarningNotifyCacheEntry(x)).ToList(); + var ruleIds = entries.Select(x => x.RuleId).ToList(); + var notifyRules = await _warningQueries.GetWarningNotifyRulesAsync(ruleIds); + + foreach (var group in notifyRules) { + } } diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index a155a5f6..454692dc 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations; using SJZY.Track.Application.Contract.Dtos.Common; using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; @@ -15,10 +16,12 @@ namespace SJZY.Track.Application.Services.ForewarningServices; public class ForewarningService : ApplicationService { private readonly IWarningRepository _warningRepository; + private readonly IForewarningCacheService _forewarningCacheService; - public ForewarningService(IWarningRepository warningRepository) + public ForewarningService(IWarningRepository warningRepository, IForewarningCacheService forewarningCacheService) { _warningRepository = warningRepository; + _forewarningCacheService = forewarningCacheService; } /// @@ -115,7 +118,7 @@ public class ForewarningService : ApplicationService }).ToList(); await _warningRepository.UpdateForewarningAsync(warning); - + return true; } @@ -145,7 +148,12 @@ public class ForewarningService : ApplicationService warning.SetEnable(isEnable); - return await _warningRepository.TurnWarningAsync(warning); + await _warningRepository.TurnWarningAsync(warning); + + // 清除缓存 + await _forewarningCacheService.DeleteRulesAsync(warning.SubSystemId, warning.CustomerId); + + return true; } /// @@ -174,17 +182,20 @@ public class ForewarningService : ApplicationService [HttpPost("ModifyTimeSpans")] public async Task ModifyTimeSpans(ModifyTimeSpanInput input) { - if (!await _warningRepository.IsAnyAsync(x => x.Id == input.WarningId)) + if (input.Items.IsNullOrEmpty()) return false; + + var warning = await _warningRepository.GetFirstAsync(x => x.Id == input.WarningId); + if (warning == null) { throw new BusinessException(message: "预警不存在"); } - if (input.Items.IsNullOrEmpty()) return false; - var warningRules = ObjectMapper.Map, List>(input.Items); await _warningRepository.ModifyTimeSpansAsync(warningRules); - + + // 清除缓存 + await _forewarningCacheService.DeleteRulesAsync(warning.SubSystemId, warning.CustomerId); return true; } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs index e06ea6ae..efa73bbd 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs @@ -59,18 +59,4 @@ public interface IWarningRepository : IBasicRepository /// /// Task GetByIdAsync(int warningId); - - /// - /// 获取预警规则列表 - /// - /// - Task?> GetWarningRule(int systemId, int customerId); - - /// - /// 获取预警规则基础信息 - /// - /// - /// - Task?> GetWarningRuleByAreaId(int areaId); - } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs index 4baac33e..56a95930 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs @@ -36,14 +36,26 @@ public class WarningRuleEntity : IFullAuditedBasicEntitys, IEntity /// /// 起始轨迹状态id /// - [SugarColumn(ColumnName = "StartTrackStatusId", IsNullable = false)] + [SugarColumn(ColumnName = "StartTrackStatusId")] public int StartTrackStatusId { get; set; } + + /// + /// 起始轨迹状态(冗余) + /// + [SugarColumn(ColumnName = "StartTrackStatusId")] + public string StartTrackStatus { get; set; } = null!; /// /// 终止轨迹状态id /// - [SugarColumn(ColumnName = "EndTrackStatusId", IsNullable = false)] + [SugarColumn(ColumnName = "EndTrackStatusId")] public int EndTrackStatusId { get; set; } + + /// + /// 终止轨迹状态(冗余) + /// + [SugarColumn(ColumnName = "EndTrackStatus")] + public string EndTrackStatus { get; set; } = null!; /// /// 货物类型 diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index 1d7be074..06972eff 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -27,6 +27,11 @@ public partial class GlobalConst /// public const string ForewarningNotifyKey = "ForewarningNotify"; + /// + /// 预警通知剩余次数redis key + /// + public const string ForewarningNotifyCntKey = "ForewarningNotifyCnt"; + /// /// kpi区域redis key前缀 /// diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs new file mode 100644 index 00000000..d39fc838 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs @@ -0,0 +1,69 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetWarningNotifiesVo +{ + /// + /// rule id + /// + public int Id { get; set; } + + /// + /// 预警名称 + /// + public string WarningName { get; set; } = null!; + + /// + /// 时效(小时) + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态(冗余) + /// + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态(冗余) + /// + public string EndTrackStatus { get; set; } = null!; + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 月份 + /// + public string? Months { get; set; } + + /// + /// 区域 + /// + public string? AreaName { get; set; } + + /// + /// 是否中转 + /// + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + public string? LeavePort { get; set; } + + /// + /// 产品编码 + /// + public string? ProductCode { get; set; } +} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Queries/IWarningQueries.cs b/src/SJZY.Track.Domain/Queries/IWarningQueries.cs new file mode 100644 index 00000000..b3652bf6 --- /dev/null +++ b/src/SJZY.Track.Domain/Queries/IWarningQueries.cs @@ -0,0 +1,27 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Queries; + +public interface IWarningQueries +{ + /// + /// 获取预警通知数据 + /// + /// + /// + Task> GetWarningNotifyRulesAsync(List ruleIds); + + + /// + /// 获取预警规则列表 + /// + /// + Task?> GetWarningRule(int systemId, int customerId); + + /// + /// 获取预警规则基础信息 + /// + /// + /// + Task?> GetWarningRuleByAreaId(int areaId); +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Queries/WarningQueries.cs b/src/SJZY.Track.Repository/Queries/WarningQueries.cs new file mode 100644 index 00000000..e9b3ec5c --- /dev/null +++ b/src/SJZY.Track.Repository/Queries/WarningQueries.cs @@ -0,0 +1,66 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Queries; + +namespace SJZY.Track.Repository.Queries; + +public class WarningQueries : ISugarRepository, IWarningQueries, + ITransientDependency +{ + public ISqlSugarClient Context { get; set; } + + public WarningQueries() + { + Context = SqlsugarScopeBasic.GetContextSafely("default"); + } + + public async Task> GetWarningNotifyRulesAsync(List ruleIds) + { + return await Context.Queryable() + .LeftJoin((a, b) => a.Id == b.WarningId) + .LeftJoin((a, b, c) => + b.WarningId == c.WarningId && b.StartTrackStatusId == c.StartTrackStatusId && + b.EndTrackStatusId == c.EndTrackStatusId) + .Where((a, b) => ruleIds.Contains(b.Id)) + .Select((a, b, c) => new GetWarningNotifiesVo + { + WarningName = a.Name + }, true) + .ToListAsync(); + } + + public Task?> GetWarningRule(int systemId, int customerId) + { + return Context.Queryable() + .InnerJoin((a, b) => a.WarningId == b.Id) + .Where((a, b) => b.IsEnable && b.SubSystemId == systemId && b.CustomerId == customerId) + .Select((a, b) => new WarningRuleCacheDto + { + Id = a.Id, + WarningId = a.WarningId, + TotalTimeSpan = a.TotalTimeSpan, + WarnTimeSpan = a.WarnTimeSpan, + WarnCount = a.WarnCount, + StartTrackStatusId = a.StartTrackStatusId, + EndTrackStatusId = a.EndTrackStatusId, + CargoType = a.CargoType, + Months = a.Months, + AreaId = a.AreaId, + IsTransit = a.IsTransit, + LeavePort = a.LeavePort, + ProductCode = a.ProductCode, + CustomerId = b.CustomerId, + SystemId = b.SubSystemId + }) + .ToListAsync(); + } + + public Task?> GetWarningRuleByAreaId(int areaId) + { + return Context.Queryable() + .InnerJoin((a, b) => a.WarningId == b.Id) + .Where((a, b) => b.IsEnable && a.AreaId == areaId) + .Select((a, b) => new RuleAreaBaseInfo(b.CustomerId, b.SubSystemId)) + .ToListAsync(); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs index 61463fe0..fe25f1d7 100644 --- a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs @@ -109,40 +109,4 @@ public class WarningRepository : BasicRepository, IWarningReposit return warning; } - - public Task?> GetWarningRule(int systemId, int customerId) - { - return Context.Queryable() - .InnerJoin((a, b) => a.WarningId == b.Id) - .Where((a,b)=>b.IsEnable && b.SubSystemId == systemId && b.CustomerId == customerId) - .Select((a,b)=>new WarningRuleCacheDto - { - Id = a.Id, - WarningId = a.WarningId, - TotalTimeSpan = a.TotalTimeSpan, - WarnTimeSpan = a.WarnTimeSpan, - WarnCount = a.WarnCount, - StartTrackStatusId = a.StartTrackStatusId, - EndTrackStatusId = a.EndTrackStatusId, - CargoType = a.CargoType, - Months = a.Months, - AreaId = a.AreaId, - IsTransit = a.IsTransit, - LeavePort = a.LeavePort, - ProductCode = a.ProductCode, - CustomerId = b.CustomerId, - SystemId = b.SubSystemId - }) - .ToListAsync(); - } - - public Task?> GetWarningRuleByAreaId(int areaId) - { - return Context.Queryable() - .InnerJoin((a, b) => a.WarningId == b.Id) - .Where((a,b)=>b.IsEnable && a.AreaId==areaId) - .Select((a,b)=>new RuleAreaBaseInfo(b.CustomerId,b.SubSystemId)) - .ToListAsync(); - } - } \ No newline at end of file diff --git a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj index 35617f6a..1c38bf3e 100644 --- a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj +++ b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj @@ -17,4 +17,16 @@ + + + + + + + + + + + + diff --git a/src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs b/src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs deleted file mode 100644 index b3c2ff5b..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs +++ /dev/null @@ -1,59 +0,0 @@ -using SJZY.Track.Domain.SeedWork; - -namespace SJZY.Track.Repository.TrackPushRecord.Entitys -{ - /// - /// 轨迹推送记录 - /// - [SugarTable("t_track_push_record")] - public class TrackPushRecordEntity : IAggregateRoot - { - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 创建时间(推送时间) - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 创建人(推送人) - /// - [SugarColumn(ColumnName = "CreateUserId")] - public int CreateUserId { get; set; } - - /// - /// 是否自动推送 - /// - [SugarColumn(ColumnName = "IsAutoPush")] - public bool IsAutoPush { get; set; } - - /// - /// 推送内容 - /// - [SugarColumn(ColumnName = "PushContent")] - public string PushContent { get; set; } = null!; - - /// - /// 接口通请求id - /// - [SugarColumn(ColumnName = "RequestId")] - public string RequestId { get; set; } = null!; - - /// - /// 服务商id - /// - [SugarColumn(ColumnName = "ServiceProviderId")] - public int ServiceProviderId { get; set; } - - /// - /// 推送轨迹总数 - /// - [SugarColumn(ColumnName = "TrackTotal")] - public int TrackTotal { get; set; } - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs b/src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs deleted file mode 100644 index 686a3402..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using SJZY.Track.Repository.TrackPushRecord.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecord.Services -{ - public interface ITrackPushRecordRepository : ISimpleClient - { - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs b/src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs deleted file mode 100644 index e8e16ab9..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SJZY.Track.Repository.Repositories; -using SJZY.Track.Repository.TrackPushRecord.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecord.Services -{ - public class TrackPushRecordRepository : BasicRepository, ITrackPushRecordRepository, IScopedDependency - { - - } -} diff --git a/src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs b/src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs deleted file mode 100644 index 64208102..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs +++ /dev/null @@ -1,47 +0,0 @@ -using SJZY.Track.Domain.SeedWork; - -namespace SJZY.Track.Repository.TrackPushRecordDetails.Entitys -{ - /// - /// 轨迹推送明细表 - /// - [SugarTable("t_track_push_record_details")] - public class TrackPushRecordDetailsEntity : IAggregateRoot - { - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 创建时间(消费完成时间) - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 异常信息 - /// - [SugarColumn(ColumnName = "ErrorMessage")] - public string ErrorMessage { get; set; } - - /// - /// 是否成功 - /// - [SugarColumn(ColumnName = "IsSuccess")] - public bool IsSuccess { get; set; } - - /// - /// 订单id - /// - [SugarColumn(ColumnName = "OrderId")] - public int OrderId { get; set; } - - /// - /// 推送记录id - /// - [SugarColumn(ColumnName = "PushRecordId")] - public int PushRecordId { get; set; } - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs b/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs deleted file mode 100644 index f84fafa7..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using SJZY.Track.Repository.TrackPushRecordDetails.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecordDetails.Services -{ - public interface ITrackPushRecordDetailsRepository : ISimpleClient - { - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs b/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs deleted file mode 100644 index 3a8c025b..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SJZY.Track.Repository.Repositories; -using SJZY.Track.Repository.TrackPushRecordDetails.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecordDetails.Services -{ - public class TrackPushRecordDetailsRepository : BasicRepository, ITrackPushRecordDetailsRepository, IScopedDependency - { - - } -} From 5cd6c4f6c6a80091293f541d2687aca2a87a3359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Thu, 1 Aug 2024 09:26:01 +0800 Subject: [PATCH 58/60] =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E9=A2=84=E8=AD=A6=EF=BC=88=E3=80=8B12?= =?UTF-8?q?=E5=B0=8F=E6=97=B6=E6=B2=A1=E6=9C=89=E6=8E=A8=E9=80=81=E7=9A=84?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProvideServices/TrackPushService.cs | 4 +- .../OrderAggregate/IOrderRepository.cs | 6 +++ .../Repositories/OrderRepository.cs | 45 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs index c9a53360..fe78e2dd 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs @@ -98,10 +98,12 @@ public class TrackPushService : ApplicationService foreach (var dateTime in dateTimes) { var rows = 0; + var pageindex = 1; do { - rows = await _orderRepository.PushWarnOrdersAsync(pageSize,dateTime); + rows = await _orderRepository.PushWarnOrdersAsync(pageSize,pageindex,dateTime); total+=rows; + pageindex++; await Task.Delay(waitTime); }while (rows!= pageSize); } diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs index 746cf6b5..7f7c6d8f 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs @@ -31,6 +31,12 @@ public interface IOrderRepository : IBasicRepository /// Task PushWarnOrdersAsync(int pageSize,DateTime createTime); + /// + /// 更新推送预警单 + /// + /// + Task PushWarnOrdersAsync(int pageSize, int pageindex, DateTime createTime); + /// /// 更新缺失标记,时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 /// diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index ff1fdfdf..ef481d06 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -1,5 +1,6 @@ using SJZY.Track.Domain; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Aggregates.TrackPushAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Order; @@ -73,6 +74,50 @@ WHERE `b`.`IsCompleted` = 0 AND `b`.`QuestionType` != 1 AND `b`.`CreateTime` < @ AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0 limit @pageSize", new { pageSize,createTime }); } + /// + /// 更新推送预警单 + /// + /// + /// + /// + /// + public async Task PushWarnOrdersAsync(int pageSize,int pageindex, DateTime createTime) + { + var ordersToUpdate = await Context.Queryable() + .LeftJoin((b, a) => a.SubSystemId == b.SubSystemId && a.CustomId == b.CustomId) + .Where((b, a) => + !b.IsCompleted + && b.QuestionType != 1 + && b.CreateTime < createTime + && !a.IsDeleted + && !b.IsDeleted) + .Select((b, a) => b) + .ToPageListAsync(pageindex,pageSize); + + var latestPushTimeIds = new LinkedList(); + var questionZeroIds = new LinkedList(); + foreach (var item in ordersToUpdate) + { + var questionType = item.LatestPushTime == null + || item.LatestPushTime < DateTime.Now.AddHours(-12) ? 2 : 0; + if(item.QuestionType== questionType) continue; + if(questionType==2) latestPushTimeIds.AddLast(item.Id); + else questionZeroIds.AddLast(item.Id); + } + + int rows = 0; + if(latestPushTimeIds.Count>0)rows+= UpdateOrderQuestionType(2, latestPushTimeIds); + if(questionZeroIds.Count>0)rows+= UpdateOrderQuestionType(0, questionZeroIds); + return rows; + } + + private int UpdateOrderQuestionType(int questionType, IEnumerable ids) + { + var idsString = string.Join(",", ids); + return Context.Ado.ExecuteCommand( + $"UPDATE `t_order` SET `QuestionType` = @questionType ,UpdateTime= current_timestamp WHERE `Id` IN ({idsString})", new { questionType }); + } + #region 订单关联 public async Task> GetLinkedOrdersAsync(int[] orderIds) From 1931ffda887d31630bdba1290a05a2329fdfdf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=9F=E5=96=9C=E6=97=BA?= Date: Thu, 1 Aug 2024 17:18:50 +0800 Subject: [PATCH 59/60] =?UTF-8?q?feat:=20=E5=85=9C=E5=BA=95=E8=BD=A8?= =?UTF-8?q?=E8=BF=B9=E8=AF=A6=E6=83=85=E6=8E=A5=E5=8F=A3=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs | 5 +++++ .../Repositories/TrackPullConfigRepository.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs index 05d748fe..ea5f1d27 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs @@ -68,4 +68,9 @@ public class GetTrackPullContentDetailOutputVO /// 是否完结 /// public bool IsCompleted { get; set; } + + /// + /// 轨迹时区兜底地址值 + /// + public int? TrackTimePlaceValue { get; set; } } \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs index 41d9053b..2c313138 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs @@ -87,6 +87,7 @@ public class TrackPullConfigRepository : BasicRepository, { Id = pullContent.Id, Code = trackContent.Code + "-" + trackContent.Content, + TrackTimePlaceValue = pullContent.TrackZonePlaceValue, }, true) .Mapper(x => { From 19b4ef80b573d92fc96b7ede123c84fcd001e22e Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 2 Aug 2024 09:05:52 +0800 Subject: [PATCH 60/60] =?UTF-8?q?temp=EF=BC=9A=E4=B8=B4=E6=97=B6=E9=A2=84?= =?UTF-8?q?=E8=AD=A6=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Forewarning/ForewarningRuleCacheEntry.cs | 5 -- ...TrackChangeAfterUpdateOrderEventHandler.cs | 3 +- .../Helpers/ForewarningHelper.cs | 4 +- .../ForewarningNotifyService.cs | 83 +++++++++++++++---- .../ForewarningServices/ForewarningService.cs | 2 + .../ForewarningAggregate/WarningEntity.cs | 8 +- .../Dtos/Forewarning/GetWarningNotifiesVo.cs | 72 ++++++++++++++-- src/SJZY.Track.Domain/Enums/RuleFactorType.cs | 2 +- .../Queries/WarningQueries.cs | 35 ++++++-- 9 files changed, 172 insertions(+), 42 deletions(-) diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs index fd9e30e2..6a00ddb7 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs @@ -46,11 +46,6 @@ public class ForewarningRuleCacheEntry /// 月份 /// public List? Months { get; set; } - - /// - /// 区域 - /// - public AreaCacheEntry? Area { get; set; } /// /// 区域 diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index 9c642169..85d0ef57 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -4,7 +4,6 @@ using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; @@ -63,7 +62,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa { var config = await _trackPullCacheService.GetPullParamWithContentConfigAsync(provider.SubSystemId, provider.ServiceProviderId); - if (!string.IsNullOrEmpty(config?.ParamConfig?.TrackContentCode) && config.ParamConfig.TrackContentCode!.ToLower() == @event.TrackCode.ToLower()) + if (!string.IsNullOrEmpty(config?.ParamConfig.TrackContentCode) && config.ParamConfig.TrackContentCode!.ToLower() == @event.TrackCode.ToLower()) { // 触发拉取节点 order.IsTriggerPull = 1; diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs index 50ea1424..a1a0e3bc 100644 --- a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -103,7 +103,7 @@ public class ForewarningHelper rules[row].Months = strValue; break; - case RuleFactorType.Areas: + case RuleFactorType.Area: if (value.Type is not JTokenType.Integer) { throw new BusinessException(message: "分区请传id"); @@ -215,7 +215,7 @@ public class ForewarningHelper case RuleFactorType.Months: dynamicRuleDict[nameof(rule.Months)] = rule.Months; break; - case RuleFactorType.Areas: + case RuleFactorType.Area: dynamicRuleDict[nameof(rule.Area)] = rule.Area; break; case RuleFactorType.IsTransit: diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs index ea453aca..efaaa7d0 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -1,8 +1,8 @@ +using System.Text; using FreeRedis; using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Dtos.Forewarning; using SJZY.Track.Application.Contract.Services; -using SJZY.Track.Domain.Aggregates.ForewarningAggregate; using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; @@ -54,18 +54,28 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep ).ForEach(rule => { dels.Add((rule.Id, order.Id)); }); } + var tran = RedisHelper.Client.Multi(); - await RedisHelper.Client.HSetAsync(GlobalConst.ForewarningNotifyCntKey, - adds.ToDictionary(x => $"{x.ruleId}_{x.orderId}", x => x.cnt)); - await RedisHelper.Client.ZAddAsync(GlobalConst.ForewarningNotifyKey, adds.Select(x => + // 维护预警队列 + foreach (var kvp in adds.ToDictionary(x => $"{x.ruleId}_{x.orderId}", x => x.cnt)) + { + await tran.HSetNxAsync(GlobalConst.ForewarningNotifyCntKey, kvp.Key, kvp.Value); // nx: not exist + } + + await tran.ZAddAsync(GlobalConst.ForewarningNotifyKey, adds.Select(x => { var entry = new WarningNotifyCacheEntry(x.ruleId, x.orderId); - return new ZMember(entry.ToString(), x.ts); + return new ZMember(entry.ToString(), x.ts); // update timestamp }).ToArray()); - await RedisHelper.Client.HDelAsync(GlobalConst.ForewarningNotifyCntKey, + + // 移出预警队列 + await tran.HDelAsync(GlobalConst.ForewarningNotifyCntKey, dels.Select(x => $"{x.ruleId}_{x.orderId}").ToArray()); - // await RedisHelper.Client.ZRemAsync(GlobalConst.ForewarningNotifyKey, - // dels.Select(x => $"{x.ruleId}:{x.orderId}").ToArray()); + await tran.ZRemAsync(GlobalConst.ForewarningNotifyKey, + dels.Select(x => $"{x.ruleId}:{x.orderId}").ToArray()); + var res = tran.Exec(); + + if (res == null) throw new BusinessException(message: "轨迹预警计算失败"); } private static List MatchRule(List rules, @@ -99,18 +109,28 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep if (!order.Month.IsIn(rule.Months)) continue; } - if (rule.Area != null) + if (!rule.Areas.IsNullOrEmpty()) { - if (order.ArrivalCountry != rule.Area.Country) continue; - if (!rule.Area.LeftPostcode.IsNullOrEmpty() && !rule.Area.RightPostcode.IsNullOrEmpty()) + var inArea = false; + foreach (var area in rule.Areas!.Where(area => order.ArrivalCountry == area.Country)) { - // todo: 参考小包的邮编匹配 + if (!area.LeftPostcode.IsNullOrEmpty() && !area.RightPostcode.IsNullOrEmpty()) + { + // tips: 参考小包的邮编匹配,字典序 + if (string.CompareOrdinal(order.ArrivalPostCode, area.LeftPostcode) < 0 || + string.CompareOrdinal(order.ArrivalPostCode, area.RightPostcode) > 0) continue; + } + + if (!area.City.IsNullOrEmpty() && order.ArrivalCity != area.City) continue; + if (!area.Province.IsNullOrEmpty() && order.ArrivalProvince != area.Province) continue; + inArea = true; + break; } - if (!rule.Area.City.IsNullOrEmpty() && order.ArrivalCity != rule.Area.City) continue; - if (!rule.Area.Province.IsNullOrEmpty() && order.ArrivalProvince != rule.Area.Province) continue; + if (!inArea) continue; } + // 命中规则 res.Add(rule); } @@ -121,16 +141,43 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep { var max = GetTimestamp(DateTime.Now); var set = await RedisHelper.Client.ZRangeByScoreAsync(GlobalConst.ForewarningNotifyKey, 0, max); - + if (set.IsNullOrEmpty()) return; var entries = set.Select(x => new WarningNotifyCacheEntry(x)).ToList(); var ruleIds = entries.Select(x => x.RuleId).ToList(); var notifyRules = await _warningQueries.GetWarningNotifyRulesAsync(ruleIds); - - foreach (var group in notifyRules) + + /* + * +预警名称:字节全程时效 +预警规则: +{起飞-落地+普货+12345678+美国 时效9,预警时效7,次数3} 命中订单总数:124,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder +{清关-提货+普货+12345678+美国 时效4,预警时效3,次数1} 命中订单总数:3250,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder +预警名称:字节全程时效 +预警规则: +{起飞-落地+普货+12345678+美国 时效9,预警时效7,次数3} 命中订单总数:124,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder +{清关-提货+普货+12345678+美国 时效4,预警时效3,次数1} 命中订单总数:3250,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder + */ + foreach (var group in notifyRules.GroupBy(x => new { x.NotifyMode, x.NotifyUserId })) { - + var notifyContent = new StringBuilder(); + + foreach (var warningGroup in group.GroupBy(x => x.WarningName)) + { + notifyContent.AppendLine($"预警名称:{warningGroup.Key}"); + notifyContent.AppendLine($"预警规则:"); + + foreach (var rule in warningGroup.ToList()) + { + var cnt = entries.Count(x => x.RuleId == rule.RuleId); + if (cnt > 0) + { + notifyContent.AppendLine( + $"{rule.ToString()} 命中订单总数:{cnt},详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder"); + } + } + } } } diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs index 454692dc..0c7be38f 100644 --- a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -53,6 +53,8 @@ public class ForewarningService : ApplicationService } warning.WarningRules = ForewarningHelper.CalcRuleList(input.TrackStatusSpans, input.WarningFactors); + warning.FactorTypeSort = input.WarningFactors.Select(x => x.FactorType).JoinAsString(","); + warning.WarningFactors = ForewarningHelper.MapFactorEntities(input.WarningFactors); warning.WarningNotifies = ForewarningHelper.MapNotifyEntities(input); await _warningRepository.CreateForewarningAsync(warning); diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs index abfc0064..4d8cea7e 100644 --- a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs @@ -27,9 +27,15 @@ public class WarningEntity: IFullAuditedBasicEntitys, IAggregateRoot /// /// 规则模板名称,KPI名称 /// - [SugarColumn(ColumnName = "Name", Length = 64)] + [SugarColumn(ColumnName = "Name")] public string Name { get; set; } = null!; + /// + /// 因素类型排序 + /// + [SugarColumn(ColumnName = "FactorTypeSort")] + public string FactorTypeSort { get; set; } = null!; + /// /// 是否启用,默认否 /// diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs index d39fc838..54ecfdb5 100644 --- a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs @@ -1,17 +1,21 @@ +using System.Text; +using NUglify.Helpers; +using SJZY.Track.Domain.Enums; + namespace SJZY.Track.Domain.Dtos.Forewarning; public class GetWarningNotifiesVo { - /// - /// rule id + /// + /// 规则 id /// - public int Id { get; set; } + public int RuleId { get; set; } /// /// 预警名称 /// public string WarningName { get; set; } = null!; - + /// /// 时效(小时) /// @@ -26,7 +30,7 @@ public class GetWarningNotifiesVo /// 提醒次数 /// public int WarnCount { get; set; } - + /// /// 起始轨迹状态(冗余) /// @@ -66,4 +70,62 @@ public class GetWarningNotifiesVo /// 产品编码 /// public string? ProductCode { get; set; } + + /// + /// 通知方式 + /// + public NotifyMode NotifyMode { get; set; } + + /// + /// 通知模板 + /// + public string NotifyTemplate { get; set; } = null!; + + /// + /// 通知人 + /// + public int NotifyUserId { get; set; } + + /// + /// 因素类型排序 + /// + public string FactorTypeSort { get; set; } = null!; + + + public override string ToString() + { + // {起飞-落地+普货+1/2/3/4+美国 时效9,预警时效7,次数3} + var res = new StringBuilder(); + res.Append('{'); + res.Append($"{StartTrackStatus}-{EndTrackStatus}"); + FactorTypeSort.Split(",").Select(Enum.Parse).ForEach(factorType => + { + switch (factorType) + { + case RuleFactorType.CargoType: + res.Append($"+{CargoType}"); + break; + case RuleFactorType.Months: + res.Append($"+{Months}"); + break; + case RuleFactorType.Area: + res.Append($"+{AreaName}"); + break; + case RuleFactorType.IsTransit: + res.Append($"+{(IsTransit?? false? "中转":"直飞")}"); + break; + case RuleFactorType.LeavePort: + res.Append($"+{LeavePort}"); + break; + case RuleFactorType.ProductCode: + res.Append($"+{ProductCode}"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(factorType), factorType, null); + } + }); + res.Append($" 时效{TotalTimeSpan},预警时效{WarnTimeSpan},次数{WarnCount}}}"); + + return res.ToString(); + } } \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Enums/RuleFactorType.cs b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs index 5ff3e3e5..6dd01ace 100644 --- a/src/SJZY.Track.Domain/Enums/RuleFactorType.cs +++ b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs @@ -19,7 +19,7 @@ public enum RuleFactorType /// /// 表示分区或区域。 /// - Areas, + Area, /// /// 指示货物是否中转。 diff --git a/src/SJZY.Track.Repository/Queries/WarningQueries.cs b/src/SJZY.Track.Repository/Queries/WarningQueries.cs index e9b3ec5c..9772f425 100644 --- a/src/SJZY.Track.Repository/Queries/WarningQueries.cs +++ b/src/SJZY.Track.Repository/Queries/WarningQueries.cs @@ -1,4 +1,5 @@ using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; using SJZY.Track.Domain.Dtos.Forewarning; using SJZY.Track.Domain.Queries; @@ -17,15 +18,33 @@ public class WarningQueries : ISugarRepository, IWarningQueries, public async Task> GetWarningNotifyRulesAsync(List ruleIds) { return await Context.Queryable() - .LeftJoin((a, b) => a.Id == b.WarningId) - .LeftJoin((a, b, c) => - b.WarningId == c.WarningId && b.StartTrackStatusId == c.StartTrackStatusId && - b.EndTrackStatusId == c.EndTrackStatusId) - .Where((a, b) => ruleIds.Contains(b.Id)) - .Select((a, b, c) => new GetWarningNotifiesVo + .LeftJoin((w, wr) => w.Id == wr.WarningId) + .LeftJoin((w, wr, a) => wr.AreaId == a.Id) + .LeftJoin((w, wr, a, wn) => + wr.WarningId == wn.WarningId && wr.StartTrackStatusId == wn.StartTrackStatusId && + wr.EndTrackStatusId == wn.EndTrackStatusId) + .Filter(null, true) // 支持历史规则 + .Where((w, wr) => ruleIds.Contains(wr.Id)) + .Select((w, wr, a, wn) => new GetWarningNotifiesVo { - WarningName = a.Name - }, true) + RuleId = wr.Id, + WarningName = w.Name, + TotalTimeSpan = wr.TotalTimeSpan, + WarnTimeSpan = wr.WarnTimeSpan, + WarnCount = wr.WarnCount, + StartTrackStatus = wr.StartTrackStatus, + EndTrackStatus = wr.EndTrackStatus, + CargoType = wr.CargoType, + Months = wr.Months, + AreaName = a.Name, + IsTransit = wr.IsTransit, + LeavePort = wr.LeavePort, + ProductCode = wr.ProductCode, + NotifyMode = wn.NotifyMode, + NotifyTemplate = wn.NotifyTemplate, + NotifyUserId = wn.NotifyUserId, + FactorTypeSort = w.FactorTypeSort + }) .ToListAsync(); }