feat: 预警功能相关代码

This commit is contained in:
DESKTOP-S2TSHMH\BSI 2024-07-24 08:54:56 +08:00
parent 0d28d10ef8
commit 895e12762d
66 changed files with 2450 additions and 1 deletions

View File

@ -51,4 +51,19 @@ public class UpdateOrderInput : OrderNoInfo
/// 订单航班信息
/// </summary>
public List<OrderFlightInfo> FlightInfos { get; set; } = new();
/// <summary>
/// 货物类型
/// </summary>
public string? CargoType { get; set; }
/// <summary>
/// 是否转运
/// </summary>
public bool? IsTransfer { get; set; }
/// <summary>
/// 产品编码
/// </summary>
public string? ProductCode { get; set; }
}

View File

@ -12,5 +12,8 @@
<PackageReference Include="SJZY.Expand.ABP.Common" Version="7.0.11" />
<PackageReference Include="Volo.Abp.Core" Version="7.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SJZY.Track.Domain\SJZY.Track.Domain.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,30 @@
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Application.Contract.Services;
/// <summary>
/// 预警通知服务接口定义。
/// 提供创建、删除预警通知和发送通知的功能。
/// </summary>
public interface IForewarningNotifyService
{
/// <summary>
/// 创建预警通知。
/// </summary>
/// <param name="order">预警订单模型。</param>
/// <returns>创建操作的结果,以整数形式返回。</returns>
Task<int> CreateForewarningNotify(ForewarningOrderModel order);
/// <summary>
/// 删除预警通知。
/// </summary>
/// <param name="order">预警订单模型。</param>
/// <returns>删除操作的结果,以整数形式返回。</returns>
Task<int> DeleteForewarningNotify(ForewarningOrderModel order);
/// <summary>
/// 发送通知。
/// </summary>
/// <param name="intervalMinute">通知间隔时间,以分钟为单位。</param>
void SendNotification(int intervalMinute);
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Application.Contract.Services;
public interface IKpiAreaCacheService
{
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Application.Contract.Services;
public interface INotifyService
{
void SendNotification(string body);
}

View File

@ -0,0 +1,32 @@
using SJZY.Track.Domain.Aggregates.ForewarningAggregate;
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Application.Contract.Services;
/// <summary>
/// 定义了与规则因子缓存相关的服务接口。
/// </summary>
public interface IRuleFactorCacheService
{
/// <summary>
/// 获取所有因子收集的规则。
/// </summary>
/// <returns>规则数组。</returns>
Task<ForewarningRule[]> GetAllFactorCollect();
/// <summary>
/// 获取所有规则因子。
/// </summary>
/// <returns>规则因子实体列表。</returns>
Task<List<RuleFactor>> GetAllRuleFactor();
/// <summary>
/// 清除因子缓存。
/// </summary>
void ClearFactorCache();
/// <summary>
/// 清除规则缓存。
/// </summary>
void ClearRuleCache();
}

View File

@ -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<CreateRuleFactorRequest, RuleEntity>(MemberList.None);
CreateMap<RuleTrackStateDto, RuleTrackStateModel>();
CreateMap<FactorItemDto, FactorItemModel>();
CreateMap<RuleAreaEntity, AreaDto>();
CreateMap<UpdateRuleAreaRequest, RuleAreaEntity>(MemberList.None);
CreateMap<AddRuleAreaInfoRequest, RuleAreaInfoEntity>(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<CreateRuleAreaRequest, RuleAreaEntity>(MemberList.None)
.ForMember(dest => dest.SubSystemId, opt => opt.MapFrom(src => src.SystemId))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name));
CreateMap<UpdateRuleAreaInfoRequest, RuleAreaInfoEntity>(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<CreateRuleFactorRequest, RuleFactorEntity>(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));
}
}

View File

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

View File

@ -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<T>(Span<RuleCollectEntity> ruleCollect,int total,IReadOnlyList<T> values,Action<RuleCollectEntity,T> action)
{
if (values.Count == 0)
{
return;
}
var segment = total / values.Count;
for(int index=0;index<values.Count;index++)
{
var start = index * segment;
var assignmentSlice = ruleCollect.Slice(start, segment);
foreach (var item in assignmentSlice)
{
action(item,values[index]);
}
}
}
private static Span<RuleCollectEntity> AllocateFactor(int total,int ruleId)
{
Span<RuleCollectEntity> 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;
}
}

View File

@ -29,4 +29,8 @@
<ProjectReference Include="..\SJZY.Track.Domain\SJZY.Track.Domain.csproj" />
<ProjectReference Include="..\SJZY.Track.Application.Contract\SJZY.Track.Application.Contract.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Validations\Forewarning\FactorItemDtoValidator.cs" />
</ItemGroup>
</Project>

View File

@ -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;
/// <summary>
/// 单例服务,用于处理预警通知
/// </summary>
public class ForewarningNotifyService:IForewarningNotifyService,ITransientDependency
{
private IRuleFactorCacheService _ruleFactorCache;
IReadOnlyDictionary<string,List<ForewarningRule>> _ruleGroupDict;
IReadOnlyDictionary<string,List<RuleFactor>> _factorDict;
private IReadOnlyDictionary<int, ForewarningRule> _rules;
readonly INotifyService _notifyService;
public ForewarningNotifyService(IRuleFactorCacheService ruleFactorCache, INotifyService notifyService)
{
_ruleFactorCache = ruleFactorCache;
_notifyService = notifyService;
}
/// <summary>
/// 创建预警通知
/// </summary>
/// <param name="order">创建预警通知需要的订单信息</param>
/// <returns>创建的通知总量,0表示没有规则</returns>
public async Task<int> CreateForewarningNotify(ForewarningOrderModel order)
{
var rules = GetRule(order);
if (rules == null || rules.Count == 0)
return 0;
return await ExecuteRule(rules,order.Id);
}
/// <summary>
/// 清除预警通知
/// </summary>
/// <param name="order">订单信息</param>
/// <returns>清理的行数</returns>
public async Task<int> DeleteForewarningNotify(ForewarningOrderModel order)
{
var rules = GetRule(order);
if (rules == null || rules.Count == 0)
return 0;
var willDeleteMembers = new List<string>();
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<string> DeleteNotifyValue(ForewarningRule rule,int orderId)
{
var members = new List<string>();
for(var index=0;index<rule.Count;index++)
{
var notifyValue = NotifyValue(rule, orderId, index);
members.Add(notifyValue);
}
return members;
}
/// <summary>
/// 获取规则
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
private List<ForewarningRule> 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<int> ExecuteRule(List<ForewarningRule> rules,int orderId)
{
var members = new List<ZMember>();
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<ZMember> ExecuteRule(ForewarningRule rule,int orderId)
{
var members = new List<ZMember>();
var intervalMinute = 60 * ((rule.Timeliness - rule.Remind) / rule.Count);// 间隔多少分钟
for(var index=0;index<rule.Count;index++)
{
var notifyTime = (rule.Remind*60) + intervalMinute * index;
var notifyTimestamp = GetTimestamp(DateTime.Now.AddMinutes(notifyTime));
var notifyValue = new ZMember(NotifyValue(rule, orderId, index),notifyTimestamp);
members.Add(notifyValue);
}
return members;
}
private long GetTimestamp(DateTime dateTime)
{
return new DateTimeOffset(dateTime).ToUnixTimeSeconds();
}
private string NotifyValue(ForewarningRule rule, int orderId,int sort)
{
var result =new RuleNotifyValue(rule.Id, orderId, sort, rule.TrackEnd);
return result.ToString();
}
private List<string> GetForewarningKeys(List<RuleFactor> factors, IForewarningFactorValue rule)
{
var keys = new List<string>();
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("未知的规则类型");
}
}
}

View File

@ -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;
}
/// <summary>
/// 创建预警模板,存在则更新
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("ModifyForewarning")]
public async ValueTask<UnifyResultDto> ModifyForewarning(CreateRuleFactorRequest input)
{
var factors = ObjectMapper.Map<CreateRuleFactorRequest,RuleFactorEntity>(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<CreateRuleFactorRequest, RuleEntity>(input);
var ruleTemplateId = await _ruleRepository.CreateForewarning(newRuleTemplate, ruleCollects);
factors.Id = ruleTemplateId.ToString();
return new UnifyResultDto(true,"保存成功");
}
/// <summary>
/// 修改时效
/// </summary>
[HttpPost("ModifyTimeliness")]
public async ValueTask<UnifyResultDto> 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<int>();
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, "更新成功");
}
/// <summary>
/// 查询预警模板列表
/// </summary>
/// <returns></returns>
[HttpPost("QueryForewarning")]
public async Task<UnifyResultDto> QueryForewarning(QueryForewarningRequest input)
{
var result = await _ruleRepository.QueryForewarning(input);
return new UnifyResultDto(true, result);
}
/// <summary>
/// 查询预警规则列表
/// </summary>
[HttpPost("QueryForewarningRules")]
public async Task<UnifyResultDto> QueryForewarningRules(QueryForewarningRuleRequest input)
{
var result = await _ruleCollectRepository.QueryForewarningRule(input);
return new UnifyResultDto(true, result);
}
/// <summary>
/// 发送预警通知
/// </summary>
[HttpPost("SendForewarningNotification")]
public void SendForewarningNotification()
{
}
}

View File

@ -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<KpiAreaInfo>(key);
if (result == null)
{
using (var globalLock = RedisHelper.Client.Lock(GlobalKpiAreaLockKey, 10))
{
result = RedisHelper.Client.Get<KpiAreaInfo>(key);
if (result != null) return;
//todo 转换成KpiAreaInfo
var kpiArea =await _kpiAreaRepository.GetAllAreaInfos();
if (kpiArea == null)
{
return;
}
RedisHelper.Client.Set(key, kpiArea, TimeSpan.FromSeconds(20));
}
}
}
}

View File

@ -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;
}
/// <summary>
/// 创建分区
/// </summary>
/// <param name="input"></param>
/// <returns>分区id</returns>
[HttpPost("KpiArea/CreateKpiArea")]
public async ValueTask<UnifyResultDto> CreateKpiArea(CreateRuleAreaRequest input)
{
var ruleAreaEntity = ObjectMapper.Map<CreateRuleAreaRequest, RuleAreaEntity>(input);
var areaId = await _ruleAreaRepository.CreateAreaAsync(ruleAreaEntity);
return new UnifyResultDto(true,areaId, "创建成功");
}
/// <summary>
/// 添加区域信息
/// </summary>
/// <param name="input"></param>
/// <returns>区域id</returns>
[HttpPost("KpiArea/AddAreaInfo")]
public async ValueTask<UnifyResultDto> AddAreaInfoAsync(AddRuleAreaInfoRequest input)
{
var ruleAreaEntity = ObjectMapper.Map<AddRuleAreaInfoRequest, RuleAreaInfoEntity>(input);
var ruleInfoId = await _ruleAreaRepository.AddAreaInfoAsync(ruleAreaEntity);
return new UnifyResultDto(true,ruleInfoId, "添加成功");
}
/// <summary>
/// 删除分区
/// </summary>
/// <param name="id">分区id</param>
/// <returns></returns>
[HttpDelete("KpiArea/DeleteKpiArea")]
public async ValueTask<UnifyResultDto> DeleteKpiArea(int id)
{
await _ruleAreaRepository.DeleteArea(id);
return new UnifyResultDto(true, "删除成功");
}
/// <summary>
/// 删除分区信息
/// </summary>
/// <param name="id">分区信息id</param>
/// <returns></returns>
[HttpDelete("KpiArea/DeleteKpiAreaInfo")]
public async ValueTask<UnifyResultDto> DeleteKpiAreaInfo(int id)
{
await _ruleAreaRepository.DeleteAreaInfo(id);
return new UnifyResultDto(true, "删除成功");
}
/// <summary>
/// 更新区域信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("KpiArea/ModifyKpiArea")]
public async Task<UnifyResultDto> 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,"更新成功");
}
/// <summary>
/// 更新区域信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("KpiArea/ModifyKpiAreaInfo")]
public async Task<UnifyResultDto> 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,"更新成功");
}
/// <summary>
/// 查询分区列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("KpiArea/GetKpiAreas")]
public async Task<UnifyPageResultDto<AreaDto>> GetKpiAreas(QueryAreaRequest input)
{
return await _ruleAreaRepository.GetAreas(input);
}
/// <summary>
/// 查询分区列表
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
[HttpPost("KpiArea/GetKpiAreaInfos")]
public async Task<UnifyPageResultDto<RuleAreaInfoDto>> GetKpiAreaInfos(QueryAreaInfoRequest query)
{
return await _ruleAreaRepository.GetAreaInfos(query);
}
}

View File

@ -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";
}
/// <summary>
/// 获取所有规则数据
/// </summary>
/// <returns></returns>
[NonAction]
public async Task<ForewarningRule[]> GetAllFactorCollect()
{
var key = GetRuleKey();
var result =await RedisHelper.Client.GetAsync<ForewarningRule[]>(key);
if (result == null)
{
using (var globalLock = RedisHelper.Client.Lock(GlobalRuleLockKey, 10))
{
result =await RedisHelper.Client.GetAsync<ForewarningRule[]>(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;
}
/// <summary>
/// 获取所有因素数据
/// </summary>
/// <returns>获取所有因素,返回值可能为空</returns>
[NonAction]
public async Task<List<RuleFactor>> GetAllRuleFactor()
{
var key = GetKey();
var result =await RedisHelper.Client.GetAsync<List<RuleFactor>>(key);
if (result == null)
{
using (var globalLock = RedisHelper.Client.Lock(GlobalFactorLockKey, 10))
{
result =await RedisHelper.Client.GetAsync<List<RuleFactor>>(key);
if (result != null) return result;
result = await GenerateAllRuleFactor();
if (result == null || result.Count == 0)
{
await RedisHelper.Client.SetAsync(key,new List<RuleFactor>() , 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<List<RuleFactor>> GenerateAllRuleFactor()
{
var factors =await _ruleFactorRepository.GetAllList();
var ruleTemplate =await _ruleRepository.GetListAsync(val => true);
var ruleMap = ruleTemplate.ToDictionary(val => val.Id);
var result = new List<RuleFactor>();
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<ForewarningRule>(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<RuleFactor> EntityToRuleFactor(RuleFactorEntity entity,RuleEntity ruleTemplate)
{
List<RuleFactor> result = new List<RuleFactor>();
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;
}
}

View File

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

View File

@ -0,0 +1,33 @@
using FluentValidation;
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Application.Validations.Forewarning;
public class CreateRuleFactorValidation : AbstractValidator<CreateRuleFactorRequest>
{
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.");
}
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Application.Validations.Forewarning;
public class FactorItemDtoValidator
{
}

View File

@ -0,0 +1,15 @@
using FluentValidation;
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Application.Validations.Forewarning;
public class RuleTrackStateDtoValidator : AbstractValidator<RuleTrackStateDto>
{
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.");
}
}

View File

@ -0,0 +1,16 @@
using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public class FactorItemModel
{
/// <summary>
/// Gets or sets the sort order.
/// </summary>
public int Sort { get; set; }
/// <summary>
/// Gets or sets the type of the rule factor.
/// </summary>
public RuleFactorType FactorType { get; set; }
}

View File

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

View File

@ -0,0 +1,13 @@
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public interface IRuleCollectRepository:IBasicRepository<RuleCollectEntity>
{
/// <summary>
/// 查询分页
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<UnifyPageResultDto<RuleCollectDto>> QueryForewarningRule(QueryForewarningRuleRequest input);
}

View File

@ -0,0 +1,10 @@
using SJZY.Expand.ElasticSearch.Services;
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public interface IRuleFactorRepository:IElasticsearchClientService<RuleFactorEntity>
{
Task<List<RuleFactorEntity>> GetFactorByIdsAsync(int[] ruleIds);
Task<List<RuleFactorEntity>> GetAllList();
}

View File

@ -0,0 +1,12 @@
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public interface IRuleRepository:IBasicRepository<RuleEntity>
{
Task<int> CreateForewarning(RuleEntity rule, RuleCollectEntity[] factorList);
Task UpdateForewarning(RuleEntity rule, RuleCollectEntity[] factorList);
Task<UnifyPageResultDto<RuleEntity>> QueryForewarning(QueryForewarningRequest input);
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public class RuleAreaEntity
{
}

View File

@ -0,0 +1,110 @@
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
[SugarTable("t_rule_collect")]
public class RuleCollectEntity : IAggregateRoot,ICloneable
{
/// <summary>
/// 自增主键
/// </summary>
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
[SugarColumn(ColumnName = "RuleId")]
public int RuleId { get; set; }
/// <summary>
/// 提醒的时间(小时)
/// </summary>
[SugarColumn(ColumnName = "Remind")]
public float Remind { get; set; }
/// <summary>
/// 时效(小时)
/// </summary>
[SugarColumn(ColumnName = "Timeliness")]
public float Timeliness { get; set; }
/// <summary>
/// 提醒次数
/// </summary>
[SugarColumn(ColumnName = "Count")]
public int Count { get; set; }
/// <summary>
/// 起始轨迹
/// </summary>
[SugarColumn(ColumnName = "TrackStart", IsNullable = false)]
public int TrackStart { get; set; }
/// <summary>
/// 终止轨迹
/// </summary>
[SugarColumn(ColumnName = "TrackEnd", IsNullable = false)]
public int TrackEnd { get; set; }
/// <summary>
/// 货物类型
/// </summary>
[SugarColumn(ColumnName = "CargoType", Length = 64)]
public string CargoType { get; set; }
/// <summary>
/// 月份
/// </summary>
[SugarColumn(ColumnName = "Month", Length = 25)]
public string Month { get; set; }
/// <summary>
/// 区域
/// </summary>
[SugarColumn(ColumnName = "Area")]
public int? Area { get; set; }
/// <summary>
/// 是否中转
/// </summary>
[SugarColumn(ColumnName = "IsTransit")]
public bool? IsTransit { get; set; }
/// <summary>
/// 起运港口
/// </summary>
[SugarColumn(ColumnName = "DeparturePort")]
public string DeparturePort { get; set; }
/// <summary>
/// 产品编码
/// </summary>
[SugarColumn(ColumnName = "ProductCode")]
public string ProductCode { get; set; }
/// <summary>
/// 创建人
/// </summary>
[SugarColumn(ColumnName = "CreateUserId")]
public int CreateUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(ColumnName = "CreateTime")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新人
/// </summary>
[SugarColumn(ColumnName = "UpdateUserId")]
public int UpdateUserId { get; set; }
/// <summary>
/// 更新时间
/// </summary>
[SugarColumn(ColumnName = "UpdateTime")]
public DateTime UpdateTime { get; set; }
public object Clone()
{
var clone = this.MemberwiseClone();
return clone;
}
}

View File

@ -0,0 +1,60 @@
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
[SugarTable("t_rule")]
public class RuleEntity:IAggregateRoot
{
/// <summary>
/// 自增主键
/// </summary>
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
/// <summary>
/// 子系统id
/// </summary>
[SugarColumn(ColumnName = "SubSystemId")]
public int SubSystemId { get; set; }
/// <summary>
/// 客户id
/// </summary>
[SugarColumn(ColumnName = "CustomId")]
public int CustomId { get; set; }
/// <summary>
/// 规则模板名称,KPI名称
/// </summary>
[SugarColumn(ColumnName = "Name", Length = 64)]
public string Name { get; set; }
/// <summary>
/// 规则模板名称,KPI名称
/// </summary>
[SugarColumn(ColumnName = "CustomName", Length = 64)]
public string CustomName { get; set; }
/// <summary>
/// 创建人
/// </summary>
[SugarColumn(ColumnName = "CreateUserId")]
public int CreateUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(ColumnName = "CreateTime")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新人
/// </summary>
[SugarColumn(ColumnName = "UpdateUserId", IsNullable = false)]
public int UpdateUserId { get; set; }
/// <summary>
/// 更新时间
/// </summary>
[SugarColumn(ColumnName = "UpdateTime", IsNullable = false)]
public DateTime UpdateTime { get; set; }
}

View File

@ -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
{
/// <summary>
/// RuleId 表的id
/// </summary>
[Keyword(Index = true)]
public int RuleId { get; set; }
/// <summary>
/// 获取或设置规则跟踪状态实体的列表。
/// </summary>
public List<RuleTrackStateModel> Tracks { get; set; }
/// <summary>
/// 获取或设置因素项模型的列表。
/// </summary>
public List<FactorItemModel> FactorItems { get; set; }
/// <summary>
/// 获取或设置货物类型的列表。
/// </summary>
public List<string> CargoTypes { get; set; }
/// <summary>
/// 获取或设置月份的列表。
/// </summary>
public List<string> Months { get; set; }
/// <summary>
/// 获取或设置是否中转的列表。
/// </summary>
public List<bool> IsTransit { get; set; }
/// <summary>
/// 获取或设置区域的列表。
/// </summary>
public List<int> Areas { get; set; }
/// <summary>
/// 获取或设置起运港口的列表。
/// </summary>
public List<string> DeparturePorts { get; set; }
/// <summary>
/// 获取或设置产品编号的列表。
/// </summary>
public List<string> ProductCodes { get; set; }
}

View File

@ -0,0 +1,24 @@
namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public class RuleTrackStateModel
{
/// <summary>
/// Gets or sets the start track value.
/// </summary>
public int Start { get; set; }
/// <summary>
/// Gets or sets the end track value.
/// </summary>
public int End { get; set; }
/// <summary>
/// Gets or sets the user to notify.
/// </summary>
public string NotifyUser { get; set; }
/// <summary>
/// Gets or sets the notification template.
/// </summary>
public string NotifyTemplate { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Domain.Aggregates;
public class KPIAreaAggregate
{
}

View File

@ -0,0 +1,68 @@
using SJZY.Track.Domain.Dtos.Forewarning;
namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
public interface IKpiAreaRepository:IBasicRepository<RuleAreaEntity>
{
/// <summary>
/// 创建分区
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
ValueTask<int> CreateAreaAsync(RuleAreaEntity entity);
/// <summary>
/// 添加分区信息
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
ValueTask<int> AddAreaInfoAsync(RuleAreaInfoEntity entity);
/// <summary>
/// 删除分区信息
/// </summary>
/// <param name="areaInfoId">分区信息id</param>
/// <returns></returns>
Task<int> DeleteAreaInfo(int areaInfoId);
/// <summary>
/// 删除分区
/// </summary>
/// <param name="areaId">分区id</param>
/// <returns></returns>
ValueTask DeleteArea(int areaId);
/// <summary>
/// 更新区域信息
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
Task<int> UpdateAreaInfoAsync(RuleAreaInfoEntity entity);
/// <summary>
/// 获得分区
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
Task<UnifyPageResultDto<AreaDto>> GetAreas(QueryAreaRequest query);
/// <summary>
/// 获取分区信息
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
Task<UnifyPageResultDto<RuleAreaInfoDto>> GetAreaInfos(QueryAreaInfoRequest query);
/// <summary>
/// 获取分区信息通过id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<RuleAreaInfoEntity> GetAreaInfoById(int id);
/// <summary>
/// 获取所有区域信息
/// </summary>
/// <returns></returns>
Task<List<RuleAreaInfoEntity>> GetAllAreaInfos();
}

View File

@ -0,0 +1,50 @@
namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
[SugarTable("t_rule_area", TableDescription = "KPI分区主表")]
public class RuleAreaEntity : IAggregateRoot
{
/// <summary>
/// 自增主键
/// </summary>
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")]
public int Id { get; set; }
/// <summary>
/// 子系统id
/// </summary>
[SugarColumn(ColumnName = "SubSystemId", ColumnDescription = "子系统id")]
public int SubSystemId { get; set; }
/// <summary>
/// 分区名称KPI名称
/// </summary>
[SugarColumn(ColumnName = "Name", Length = 64, ColumnDescription = "分区名称KPI名称")]
public string Name { get; set; }
/// <summary>
/// 创建人
/// </summary>
[SugarColumn(ColumnName = "CreateUserId", ColumnDescription = "创建人")]
public int CreateUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(ColumnName = "CreateTime", ColumnDescription = "创建时间")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新人
/// </summary>
[SugarColumn(ColumnName = "UpdateUserId", ColumnDescription = "更新人")]
public int UpdateUserId { get; set; }
/// <summary>
/// 更新时间
/// </summary>
[SugarColumn(ColumnName = "UpdateTime", ColumnDescription = "更新时间")]
public DateTime UpdateTime { get; set; }
[SugarColumn(IsIgnore = true)]
public List<RuleAreaInfoEntity> AreaInfos { get; set; }
}

View File

@ -0,0 +1,71 @@
namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
[SugarTable("t_rule_area_info", TableDescription = "kpi 区域子表")]
public class RuleAreaInfoEntity : IEntity
{
/// <summary>
/// 自增主键
/// </summary>
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")]
public int Id { get; set; }
/// <summary>
/// t_rule_area 表id
/// </summary>
[SugarColumn(ColumnName = "AreaId", ColumnDescription = "t_rule_area 表id")]
public int AreaId { get; set; }
/// <summary>
/// 国家或地区
/// </summary>
[SugarColumn(ColumnName = "Country", Length = 128, ColumnDescription = "国家或地区")]
public string Country { get; set; }
/// <summary>
/// 州或者省份
/// </summary>
[SugarColumn(ColumnName = "Province", Length = 128, IsNullable = true, ColumnDescription = "州或者省份")]
public string Province { get; set; }
/// <summary>
/// 城市
/// </summary>
[SugarColumn(ColumnName = "City", Length = 128, IsNullable = true, ColumnDescription = "城市")]
public string City { get; set; }
/// <summary>
/// 起始邮编
/// </summary>
[SugarColumn(ColumnName = "LeftPostcode", Length = 10, IsNullable = true, ColumnDescription = "起始邮编")]
public string LeftPostcode { get; set; }
/// <summary>
/// 截止邮编
/// </summary>
[SugarColumn(ColumnName = "RightPostcode", Length = 10, IsNullable = true, ColumnDescription = "截止邮编")]
public string RightPostcode { get; set; }
/// <summary>
/// 创建人
/// </summary>
[SugarColumn(ColumnName = "CreateUserId", ColumnDescription = "创建人")]
public int CreateUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(ColumnName = "CreateTime", ColumnDescription = "创建时间")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新人
/// </summary>
[SugarColumn(ColumnName = "UpdateUserId", IsNullable = false, ColumnDescription = "更新人")]
public int UpdateUserId { get; set; }
/// <summary>
/// 更新时间
/// </summary>
[SugarColumn(ColumnName = "UpdateTime", IsNullable = false, ColumnDescription = "更新时间")]
public DateTime UpdateTime { get; set; }
}

View File

@ -132,6 +132,24 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot
[SugarColumn(ColumnName = "LeavePort")]
public string? LeavePort { get; set; }
/// <summary>
/// 起运港口
/// </summary>
[SugarColumn(ColumnName = "CargoType")]
public string? CargoType { get; set; }
/// <summary>
/// 起运港口
/// </summary>
[SugarColumn(ColumnName = "IsTransfer")]
public bool? IsTransfer { get; set; }
/// <summary>
/// 起运港口
/// </summary>
[SugarColumn(ColumnName = "ProductCode")]
public string? ProductCode { get; set; }
[SugarColumn(IsIgnore = true)] public List<OrderFlightEntity> OrderFlights { get; set; }
[SugarColumn(IsIgnore = true)] public List<OrderTemplateEntity> OrderTemplates { get; set; }

View File

@ -11,4 +11,9 @@ public partial class GlobalConst
/// 轨迹推送记录 es索引名称(模板)
/// </summary>
public const string TrackPushRecordsIndex = "sjzy_track_push_records";
/// <summary>
/// 预警规则 es索引名称(模板)
/// </summary>
public const string RuleFactorIndex = "sjzy_rule_factor";
}

View File

@ -21,4 +21,19 @@ public partial class GlobalConst
/// 轨迹拉取配置信息redis key前缀
/// </summary>
public const string TrackPullContentKeyPrefix = "TrackPullContent";
/// <summary>
/// 规则因素缓存redis key前缀
/// </summary>
public const string RuleFactorKeyPrefix = "RuleFactor";
/// <summary>
/// 预警通知redis key前缀
/// </summary>
public const string ForewarningNotifyKeyPrefix = "ForewarningNotity";
/// <summary>
/// kpi区域redis key前缀
/// </summary>
public const string KpiAreaKeyPrefix = "KpiArea";
}

View File

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

View File

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

View File

@ -0,0 +1,35 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class RuleAreaInfoDto
{
/// <summary>
/// 分区信息id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 分区id
/// </summary>
public int AreaId { get; set; }
/// <summary>
/// 国家或地区
/// </summary>
public string Country { get; set; }
/// <summary>
/// 省份
/// </summary>
public string Province { get; set; }
/// <summary>
/// 城市
/// </summary>
public string City { get; set; }
/// <summary>
/// 开始邮编
/// </summary>
public string LeftPostcode { get; set; }
public string RightPostcode { get; set; }
}

View File

@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class CreateRuleAreaRequest
{
/// <summary>
/// 系统id
/// </summary>
[Required]
public int SystemId { get; set; }
/// <summary>
/// 名称
/// </summary>
[Required]
public string Name { get; set; }
}

View File

@ -0,0 +1,65 @@
namespace SJZY.Track.Domain.Dtos.Forewarning
{
public class CreateRuleFactorRequest
{
/// <summary>
/// RuleId 表的id,小于0 表示创建新的规则
/// </summary>
public int RuleId { get; set; }
/// <summary>
/// 模板名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 获取或设置规则跟踪状态实体的列表。
/// </summary>
public List<RuleTrackStateDto> Tracks { get; set; }
/// <summary>
/// 获取或设置因素项模型的列表。
/// </summary>
public List<FactorItemDto> FactorItems { get; set; }
/// <summary>
/// 获取或设置货物类型的列表。
/// </summary>
public List<string> CargoTypes { get; set; }
/// <summary>
/// 获取或设置月份的列表。
/// </summary>
public List<string> Months { get; set; }
/// <summary>
/// 获取或设置是否中转的列表。
/// </summary>
public List<int> IsTransit { get; set; }
/// <summary>
/// 获取或设置区域的列表。
/// </summary>
public List<int> Areas { get; set; }
/// <summary>
/// 获取或设置起运港口的列表。
/// </summary>
public List<string> DeparturePorts { get; set; }
/// <summary>
/// 获取或设置产品编号的列表。
/// </summary>
public List<string> ProductCodes { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class FactorItemDto
{
/// <summary>
/// Gets or sets the sort order.
/// </summary>
public int Sort { get; set; }
/// <summary>
/// Gets or sets the type of the rule factor.
/// </summary>
public RuleFactorType FactorType { get; set; }
}

View File

@ -0,0 +1,30 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class ForewarningOrderModel:IForewarningFactorValue
{
/// <summary>
/// 订单id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 当前轨迹状态
/// </summary>
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; }
}

View File

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

View File

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

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class KpiAreaInfo
{
}

View File

@ -0,0 +1,34 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class ModifyTimelinessRequest
{
public List<TimelinessDto> Items { get; set; }
/// <summary>
/// 规则模板id
/// </summary>
public int RuleId { get; set; }
}
public class TimelinessDto
{
/// <summary>
/// 时效
/// </summary>
public float Timeliness { get; set; }
/// <summary>
/// 提醒时效
/// </summary>
public float Remind { get; set; }
/// <summary>
/// 提醒次数
/// </summary>
public int Count { get; set; }
/// <summary>
/// 规则id
/// </summary>
public int Id { get; set; }
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class QueryAreaInfoRequest: PageInfoInput
{
public int AreaId { get; set; }
}

View File

@ -0,0 +1,14 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class QueryAreaRequest:PageInfoInput
{
/// <summary>
/// 分区名称
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int? SystemId { get; set; }
}

View File

@ -0,0 +1,24 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class QueryForewarningRequest: PageInfoInput
{
/// <summary>
/// 子系统id
/// </summary>
public int? SystemId { get; set; }
/// <summary>
/// 客户或者模板名称
/// </summary>
public string? KeyWord { get; set; }
/// <summary>
/// 排序方式,不填不排序
/// </summary>
public string? SortField { get; set; }
/// <summary>
/// 排序方式
/// </summary>
public bool IsAsc { get; set; } = false;
}

View File

@ -0,0 +1,19 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class QueryForewarningRuleRequest: PageInfoInput
{
/// <summary>
/// kpi 预警规则模板id
/// </summary>
public int RuleId { get; set; }
/// <summary>
/// 排序方式,不填不排序
/// </summary>
public string? SortField { get; set; }
/// <summary>
/// 排序方式
/// </summary>
public bool IsAsc { get; set; } = false;
}

View File

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

View File

@ -0,0 +1,7 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class RuleCollectRequest
{
public string Name { get; set; }
}

View File

@ -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; }
/// <summary>
/// Gets or sets the start track value.
/// </summary>
public int Start { get; set; }
/// <summary>
/// Gets or sets the end track value.
/// </summary>
public int End { get; set; }
/// <summary>
/// Gets or sets the user to notify.
/// </summary>
public string NotifyUser { get; set; }
/// <summary>
/// Gets or sets the notification template.
/// </summary>
public string NotifyTemplate { get; set; }
/// <summary>
/// 获取或设置因素项模型的列表。
/// </summary>
public List<FactorItemModel> FactorItems { get; set; }
}

View File

@ -0,0 +1,42 @@
using SJZY.Track.Domain.Aggregates.ForewarningAggregate;
using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class RuleInfoModel
{
/// <summary>
/// 获取或设置因素项模型的列表。
/// </summary>
public FactorItemModel FactorItems { get; set; }
/// <summary>
/// 获取或设置货物类型的列表。
/// </summary>
public string CargoTypes { get; set; }
/// <summary>
/// 获取或设置月份的列表。
/// </summary>
public short Months { get; set; }
/// <summary>
/// 获取或设置是否中转的列表。
/// </summary>
public bool? IsTransit { get; set; }
/// <summary>
/// 获取或设置区域的列表。
/// </summary>
public int Areas { get; set; }
/// <summary>
/// 获取或设置起运港口的列表。
/// </summary>
public string DeparturePorts { get; set; }
/// <summary>
/// 获取或设置产品编号的列表。
/// </summary>
public string ProductCodes { get; set; }
}

View File

@ -0,0 +1,40 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class RuleNotifyValue
{
public int RuleId { get; set; }
public int OrderId { get; set; }
/// <summary>
/// 第几次通知
/// </summary>
public int Count { get; set; }
/// <summary>
/// 结束轨迹状态
/// </summary>
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}";
}
}

View File

@ -0,0 +1,24 @@
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class RuleTrackStateDto
{
/// <summary>
/// Gets or sets the start track value.
/// </summary>
public int Start { get; set; }
/// <summary>
/// Gets or sets the end track value.
/// </summary>
public int End { get; set; }
/// <summary>
/// Gets or sets the user to notify.
/// </summary>
public string NotifyUser { get; set; }
/// <summary>
/// Gets or sets the notification template.
/// </summary>
public string NotifyTemplate { get; set; }
}

View File

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class UpdateRuleAreaInfoRequest
{
/// <summary>
/// 分区信息id
/// </summary>
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; }
}

View File

@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace SJZY.Track.Domain.Dtos.Forewarning;
public class UpdateRuleAreaRequest
{
/// <summary>
/// 名称
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 分区id
/// </summary>
public int Id { get; set; }
}

View File

@ -0,0 +1,38 @@
namespace SJZY.Track.Domain.Enums;
/// <summary>
/// 枚举表示不同类型的规则因素。
/// </summary>
public enum RuleFactorType
{
/// <summary>
/// 表示货物类型。
/// </summary>
CargoType,
/// <summary>
/// 表示月份。
/// </summary>
Month,
/// <summary>
/// 表示分区或区域。
/// </summary>
Areas,
/// <summary>
/// 指示货物是否中转。
/// </summary>
IsTransit,
/// <summary>
/// 表示起运港口。
/// </summary>
DeparturePort,
/// <summary>
/// 表示产品编号。
/// </summary>
ProductCode
}

View File

@ -12,4 +12,9 @@
<PackageReference Include="SJZY.Expand.ElasticSearch" Version="7.0.17" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Aggregates\KPIAreaAggregate.cs" />
<Compile Remove="Aggregates\ForewarningAggregate\RuleAreaEntity.cs" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Repository.Repositories;
public class KpiAreaInfoRepository
{
}

View File

@ -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<RuleAreaEntity> ,IKpiAreaRepository,ITransientDependency
{
public async ValueTask<int> CreateAreaAsync(RuleAreaEntity entity)
{
return await InsertReturnIdentityAsync(entity);
}
public async ValueTask<int> 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<RuleAreaInfoEntity>().Where(x => x.AreaId == areaId).ExecuteCommandAsync();
transaction.Complete();
}
public Task<int> DeleteAreaInfo(int areaInfoId)
{
return Context.Deleteable<RuleAreaInfoEntity>().Where(val=>val.Id==areaInfoId).ExecuteCommandAsync();
}
public Task<int> UpdateAreaInfoAsync(RuleAreaInfoEntity entity)
{
return Context.Updateable<RuleAreaInfoEntity>(entity).ExecuteCommandAsync();
}
/// <summary>
/// 获取分区
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public async Task<UnifyPageResultDto<AreaDto>> GetAreas(QueryAreaRequest query)
{
var queryable = Context.Queryable<RuleAreaEntity>();
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<AreaDto>(val=>new AreaDto()
{
Id = val.Id,
Name = val.Name,
SubSystemId = val.SubSystemId,
UpdateTime = val.CreateTime
})
.ToPagedListAsync(query.PageIndex, query.PageSize);
}
/// <summary>
/// 获得分区信息
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public async Task<UnifyPageResultDto<RuleAreaInfoDto>> GetAreaInfos(QueryAreaInfoRequest query)
{
var queryable = Context.Queryable<RuleAreaInfoEntity>();
queryable = queryable.Where(x => x.AreaId == query.AreaId);
return await queryable.OrderBy(x => x.Id, OrderByType.Desc)
.Select<RuleAreaInfoDto>(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<RuleAreaInfoEntity> GetAreaInfoById(int id)
{
return Context.Queryable<RuleAreaInfoEntity>().FirstAsync(val => val.Id == id);
}
/// <summary>
/// 获取所有区域信息
/// </summary>
/// <returns></returns>
public Task<List<RuleAreaInfoEntity>> GetAllAreaInfos()
{
return Context.Queryable<RuleAreaInfoEntity>().ToListAsync();
}
}

View File

@ -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<RuleCollectEntity>, IRuleCollectRepository,ITransientDependency
{
/// <summary>
/// 查询预警规则分页信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public Task<UnifyPageResultDto<RuleCollectDto>> QueryForewarningRule(QueryForewarningRuleRequest input)
{
var query = Context.Queryable<RuleCollectEntity>()
.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
};
}
}

View File

@ -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<RuleFactorEntity>, IRuleFactorRepository,
ITransientDependency
{
public RuleFactorRepository(ConnectionFactory connectionFactory) : base(connectionFactory)
{
}
public async Task CreateAsync(RuleFactorEntity entity)
{
await IndexDocumentAsync(entity);
}
public async Task<List<RuleFactorEntity>> GetFactorByIdsAsync(int[] ruleIds)
{
var response = await Context.SearchAsync<RuleFactorEntity>(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<RuleFactorEntity>();
default:
throw new Exception($"数据查询失败,http status: {num},原因:{response.DebugInformation}");
}
}
/// <summary>
/// 获取所有数据
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<List<RuleFactorEntity>> GetAllList()
{
var response = await Context.SearchAsync<RuleFactorEntity>();
int num = response.ApiCall.HttpStatusCode ?? throw new Exception("数据查询失败,原因:" + response.DebugInformation);
switch (num)
{
case 200:
return response.Documents.ToList();
case 404:
return new List<RuleFactorEntity>();
default:
throw new Exception($"数据查询失败,http status: {num},原因:{response.DebugInformation}");
}
}
}

View File

@ -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<RuleEntity> ,IRuleRepository,ITransientDependency
{
public async Task<int> 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<RuleCollectEntity>().Where(x=>x.RuleId==rule.Id).ExecuteCommandAsync();
await Context.Insertable(factorList).ExecuteCommandAsync();
tran.Complete();
}
/// <summary>
/// 查询预警模板分页信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public Task<UnifyPageResultDto<RuleEntity>> QueryForewarning(QueryForewarningRequest input)
{
var query = Context.Queryable<RuleEntity>()
.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);
}
}