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