对接前端轨迹预警

This commit is contained in:
xiaolipro 2024-09-20 15:07:58 +08:00
parent c22421676c
commit 1a16606443
20 changed files with 146 additions and 79 deletions

View File

@ -26,9 +26,9 @@ public class NotifyDto
public int Id { get; set; }
/// <summary>
/// 通知人id
/// 通知人
/// </summary>
public List<int> NotifyUserIds { get; set; }
public List<NotifyUser> NotifyUsers { get; set; }
/// <summary>
/// 通知方式(1站内信,2飞书)

View File

@ -22,18 +22,26 @@ public class WarningNotifyDto
/// </summary>
public string EndTrackStatus { get; set; } = null!;
/// <summary>
/// 通知人id
/// </summary>
public List<int> NotifyUserIds { get; set; }
/// <summary>
/// 通知人
/// </summary>
public List<string> NotifyUsers { get; set; }
public List<NotifyUser> NotifyUsers { get; set; }
/// <summary>
/// 通知方式(1站内信,2飞书)
/// </summary>
public List<int> NotifyModes { get; set; }
}
public class NotifyUser
{
/// <summary>
/// 用户id
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
}

View File

@ -28,7 +28,7 @@ public class WarningNotifyCacheEntry
public int OrderId { get; set; }
/// <summary>
/// 预警次数
/// 预警次数(第几次)
/// </summary>
public int Counter { get; set; }

View File

@ -107,9 +107,11 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
// 删除轨迹(删的是同子系统下的单,所以code是统一的)
var tracks = await _trackDetailsEsRepository.GetLatestListAsync(@event.OrderIds, @event.TrackCodes);
await _trackDetailsEsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes);
var orderIds = await _trackDetailsEsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes);
var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id),
if (orderIds.Count == 0) return;
var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id),
x => new OrderEntity
{
Id = x.Id,

View File

@ -160,8 +160,7 @@ public class ForewarningHelper
StartTrackStatusId = x.StartTrackStatusId,
EndTrackStatusId = x.EndTrackStatusId,
NotifyMode = x.NotifyModes.JoinAsString(","),
NotifyUser = x.NotifyUsers.JoinAsString(","),
NotifyUserId = x.NotifyUserIds.JoinAsString(","),
NotifyUser = x.NotifyUsers.ToJson(),
}).ToList();
}
@ -180,8 +179,7 @@ public class ForewarningHelper
StartTrackStatus = statusDic.TryGetValue(x.StartTrackStatusId, out var start) ? start : "",
EndTrackStatusId = x.EndTrackStatusId,
EndTrackStatus = statusDic.TryGetValue(x.EndTrackStatusId, out var end) ? end : "",
NotifyUserIds = x.NotifyUserId.Split(',').Select(int.Parse).ToList(),
NotifyUsers = x.NotifyUser.Split(',').ToList(),
NotifyUsers = JsonConvert.DeserializeObject<List<NotifyUser>>(x.NotifyUser) ?? new List<NotifyUser>(),
NotifyModes = x.NotifyMode.Split(',').Select(int.Parse).ToList(),
}).ToList(),
WarningFactors = warning.WarningFactors.Select(x => new WarningFactorWithIdDto

View File

@ -16,4 +16,9 @@ public class TrackAppOptions
/// 轨迹兜底扫描间隔(秒)
/// </summary>
public int TrackButtomUpScanInterval { get; set; }
/// <summary>
/// 轨迹运输时效预警通知跳转地址
/// </summary>
public string WarningNotifyUrl { get; set; }
}

View File

@ -1,9 +1,11 @@
using System.Text;
using FreeRedis;
using Microsoft.Extensions.Options;
using SJZY.Expand.ABP.Core;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Track.Application.Contract.Dtos.Forewarning;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Options;
using SJZY.Track.Domain.Aggregates.ForewarningAggregate;
using SJZY.Track.Domain.Dtos.Forewarning;
using SJZY.Track.Domain.Enums;
@ -22,6 +24,7 @@ namespace SJZY.Track.Application.Services.ForewarningServices;
public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency
{
private readonly IForewarningCacheService _forewarningCacheService;
private readonly IOptionsSnapshot<TrackAppOptions> _options;
private readonly IHttpClientProxy<IRequestSendMessageService> _requestSendMessageService;
private readonly IWarningQueries _warningQueries;
private readonly IWarningRecordEsRepository _warningRecordEsRepository;
@ -29,12 +32,13 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
public ForewarningNotifyService(IWarningQueries warningQueries,
IWarningRecordEsRepository warningRecordEsRepository,
IHttpClientProxy<IRequestSendMessageService> requestSendMessageService,
IForewarningCacheService forewarningCacheService)
IForewarningCacheService forewarningCacheService, IOptionsSnapshot<TrackAppOptions> options)
{
_warningQueries = warningQueries;
_warningRecordEsRepository = warningRecordEsRepository;
_requestSendMessageService = requestSendMessageService;
_forewarningCacheService = forewarningCacheService;
_options = options;
}
@ -147,19 +151,26 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
{
var rule = notifyRules.FirstOrDefault(x => x.RuleId == entry.RuleId);
if (rule == null) continue;
warningRecords.Add(new WarningRecordIndex
foreach (var notifyUser in rule.NotifyUsers)
{
SubSystemId = rule.SubSystemId,
WarningName = rule.WarningName,
CustomName = rule.CustomName,
RuleId = entry.RuleId,
Rule = rule.ToString(),
Counter = entry.Counter,
OrderId = entry.OrderId,
WarningStatus = WarningStatus.UnProcessed,
NotifyUser = rule.NotifyUser,
CreateTime = DateTime.Now,
});
warningRecords.Add(new WarningRecordIndex
{
SubSystemId = rule.SubSystemId,
SubSystemName = rule.SubSystemName,
WarningName = rule.WarningName,
CustomName = rule.CustomName,
RuleId = entry.RuleId,
Rule = rule.ToString(),
Counter = entry.Counter,
IsLast = rule.WarnCount == entry.Counter,
OrderId = entry.OrderId,
WarningStatus = WarningStatus.UnProcessed,
NotifyUserId = notifyUser.UserId,
NotifyUserName = notifyUser.UserName,
CreateTime = DateTime.Now,
});
}
}
await _warningRecordEsRepository.BulkInsertAsync(warningRecords);
@ -172,20 +183,20 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
var userRules = new Dictionary<int, List<GetWarningNotifiesVo>>();
foreach (var rule in notifyRules)
{
foreach (var userId in rule.NotifyUserIds)
foreach (var notifyUser in rule.NotifyUsers)
{
if (!userRules.ContainsKey(userId))
if (!userRules.ContainsKey(notifyUser.UserId))
{
userRules[userId] = new List<GetWarningNotifiesVo>();
userRules[notifyUser.UserId] = new List<GetWarningNotifiesVo>();
}
userRules[userId].Add(rule);
userRules[notifyUser.UserId].Add(rule);
}
}
// 以人的维度发送通知,异步
foreach (var userRule in userRules)
{
// 以人的维度发送通知,异步
_ = DoNotifyAsync(subSystemId, userRule.Key, userRule.Value, entries,
NotifyMode.SiteInternal);
_ = DoNotifyAsync(subSystemId, userRule.Key, userRule.Value, entries, NotifyMode.FeiShu);
@ -214,7 +225,8 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
*/
var notifyContent = new StringBuilder();
foreach (var warningGroup in rules.Where(x => x.NotifyModes.Contains(mode))
foreach (var warningGroup in rules
.Where(x => x.NotifyMode.Split(',').Select(Enum.Parse<NotifyMode>).Contains(mode))
.GroupBy(x => x.WarningName))
{
notifyContent.AppendLine($"预警名称:{warningGroup.Key}");
@ -224,7 +236,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
{
var cnt = entries.Count(x => x.RuleId == rule.RuleId);
notifyContent.AppendLine(
$"{rule.ToString()} 命中订单总数:{cnt},详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder");
$"{rule.ToString()} 命中订单总数:{cnt},详情点击{_options.Value.WarningNotifyUrl}?userId={userId}");
}
}

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Dtos.Forewarning;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Helpers;
@ -114,7 +115,7 @@ public class ForewarningService : ApplicationService
{
Id = x.Id,
NotifyMode = x.NotifyModes.JoinAsString(","),
NotifyUserId = x.NotifyUserIds.JoinAsString(","),
NotifyUser = x.NotifyUsers.ToJson(),
}).ToList();
await _warningRepository.UpdateForewarningAsync(warning);

View File

@ -33,11 +33,13 @@ public class OrderWarningService : ApplicationService
/// 获取订单运输时效预警分页列表
/// </summary>
/// <param name="inputVo"></param>
/// <param name="userId"></param>
/// <returns></returns>
[HttpPost("GetOrderWarningPageList")]
public async Task<UnifyPageResultDto<GetOrderWarningPageOutput>> GetOrderWarningPageListAsync(
GetOrderWarningPageListVo inputVo)
[FromBody] GetOrderWarningPageListVo inputVo, [FromQuery] int? userId)
{
if (userId != null) inputVo.NotifyUserId = userId;
var result = await _warningRecordEsRepository.GetOrderWarningPageListAsync(inputVo);
var orderIds = result.list.Select(x => x.OrderId).ToList();
var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => new
@ -51,17 +53,18 @@ public class OrderWarningService : ApplicationService
var list = new List<GetOrderWarningPageOutput>();
result.list.ForEach(x =>
{
var item = new GetOrderWarningPageOutput
{
SubSystemName = x.SubSystemName,
Rule = x.Rule,
Counter = x.Counter,
IsLast = x.IsLast,
WarningName = x.WarningName,
WarningStatus = x.WarningStatus,
CreateTime = x.CreateTime,
NotifyUser = x.NotifyUser,
NotifyUser = x.NotifyUserName,
CustomName = x.CustomName,
};
var order = orders.FirstOrDefault(o => o.Id == x.OrderId);

View File

@ -10,6 +10,6 @@ public class RuleTrackStateDtoValidator : AbstractValidator<WarningNotifyDto>
RuleFor(x => x.StartTrackStatusId).GreaterThan(0).WithMessage("起始轨迹状态id必须大于0");
RuleFor(x => x.EndTrackStatusId).GreaterThan(0).WithMessage("终止轨迹状态id必须大于0");
RuleFor(x => x.NotifyModes).NotEmpty().WithMessage("通知方式不能为空");
RuleFor(x => x.NotifyUserIds).NotEmpty().WithMessage("通知对象不能为空");
RuleFor(x => x.NotifyUsers).NotEmpty().WithMessage("通知对象不能为空");
}
}

View File

@ -34,13 +34,7 @@ public class WarningNotifyEntity : IFullAuditedBasicEntitys, IEntity
public string NotifyMode { get; set; }
/// <summary>
/// 通知人id,多个逗号分隔
/// </summary>
[SugarColumn(ColumnName = "NotifyUserId")]
public string NotifyUserId { get; set; }
/// <summary>
/// 通知人,多个逗号分隔
/// 通知人,json格式 多个
/// </summary>
[SugarColumn(ColumnName = "NotifyUser")]
public string NotifyUser { get; set; }

View File

@ -8,10 +8,15 @@ namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate;
public class WarningRecordIndex : IdBaseIndex
{
/// <summary>
/// 子系统
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 子系统name
/// </summary>
public string SubSystemName { get; set; }
/// <summary>
/// 索引名称
/// </summary>
@ -22,6 +27,11 @@ public class WarningRecordIndex : IdBaseIndex
/// </summary>
public string WarningName { get; set; } = null!;
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 客户简称
/// </summary>
@ -47,15 +57,25 @@ public class WarningRecordIndex : IdBaseIndex
/// </summary>
public int Counter { get; set; }
/// <summary>
/// 是否最后一次
/// </summary>
public bool IsLast { get; set; }
/// <summary>
/// 预警状态
/// </summary>
public WarningStatus WarningStatus { get; set; }
/// <summary>
/// 通知用户
/// 通知用户name
/// </summary>
public string NotifyUser { get; set; }
public string NotifyUserName { get; set; }
/// <summary>
/// 通知用户id
/// </summary>
public int NotifyUserId { get; set; }
/// <summary>
/// 创建时间

View File

@ -22,7 +22,7 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
Task<List<TrackDetailsIndex>> GetListAsync(int orderId);
Task DeleteTrackAsync(int[] orderIds, List<string> trackCodes);
Task<List<int>> DeleteTrackAsync(int[] orderIds, List<string> trackCodes);
Task DeleteTrackByIdAsync(string id, string indexName);
}

View File

@ -22,9 +22,9 @@ public class GetOrderWarningPageListVo : PageInfoInput
public WarningStatus? WarningStatus { get; set; }
/// <summary>
/// 客户简称
/// 客户id
/// </summary>
public string? CustomName { get; set; }
public int? CustomId { get; set; }
/// <summary>
/// 预警名称
@ -32,9 +32,9 @@ public class GetOrderWarningPageListVo : PageInfoInput
public string? WarningName { get; set; }
/// <summary>
/// 通知用户
/// 通知用户id
/// </summary>
public string? NotifyUser { get; set; }
public int? NotifyUserId { get; set; }
/// <summary>
/// 创建时间开始

View File

@ -4,6 +4,11 @@ namespace SJZY.Track.Domain.Dtos.Forewarning;
public class GetOrderWarningPageOutput
{
/// <summary>
/// 子系统name
/// </summary>
public string SubSystemName { get; set; }
/// <summary>
/// 预警名称
/// </summary>
@ -24,6 +29,11 @@ public class GetOrderWarningPageOutput
/// </summary>
public int Counter { get; set; }
/// <summary>
/// 是否最后一次
/// </summary>
public bool IsLast { get; set; }
/// <summary>
/// 预警状态
/// </summary>

View File

@ -7,10 +7,15 @@ namespace SJZY.Track.Domain.Dtos.Forewarning;
public class GetWarningNotifiesVo
{
/// <summary>
/// 子系统
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 子系统name
/// </summary>
public string SubSystemName { get; set; }
/// <summary>
/// 规则 id
/// </summary>
@ -37,7 +42,7 @@ public class GetWarningNotifiesVo
public float WarnTimeSpan { get; set; }
/// <summary>
/// 提醒次数
/// 提醒次数(总次数)
/// </summary>
public int WarnCount { get; set; }
@ -82,21 +87,17 @@ public class GetWarningNotifiesVo
public string? ProductCode { get; set; }
/// <summary>
/// 通知方式
/// 通知方式(多个逗号拼接)
/// </summary>
public string NotifyMode { get; set; }
public List<NotifyMode> NotifyModes { get; set; }
/// <summary>
/// 通知人
/// 通知用户(json多个)
/// </summary>
public string NotifyUserId { get; set; }
public List<int> NotifyUserIds { get; set; }
public string NotifyUser { get; set; }
public List<NotifyUserVo> NotifyUsers { get; set; }
/// <summary>
/// 因素类型排序
/// </summary>
@ -140,3 +141,16 @@ public class GetWarningNotifiesVo
return res.ToString();
}
}
public class NotifyUserVo
{
/// <summary>
/// 用户id
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
}

View File

@ -1,7 +1,7 @@
using Newtonsoft.Json;
using SJZY.Track.Domain.Aggregates.ForewarningAggregate;
using SJZY.Track.Domain.Aggregates.KPIAreaAggregate;
using SJZY.Track.Domain.Dtos.Forewarning;
using SJZY.Track.Domain.Enums;
using SJZY.Track.Domain.Queries;
using SJZY.Track.Domain.VEntities;
@ -21,11 +21,13 @@ public class WarningQueries : ISugarRepository, IWarningQueries,
wr.WarningId == wn.WarningId && wr.StartTrackStatusId == wn.StartTrackStatusId &&
wr.EndTrackStatusId == wn.EndTrackStatusId)
.LeftJoin<VExternalSubjectEntity>((w, wr, a, wn, cus) => w.CustomerId == cus.Id)
.LeftJoin<VSystemEntity>((w, wr, a, wn, cus, system) => w.SubSystemId == system.Id)
.Filter(null, true) // 支持历史规则
.Where((w, wr) => ruleIds.Contains(wr.Id))
.Select<GetWarningNotifiesVo>((w, wr, a, wn, cus) => new GetWarningNotifiesVo
.Select<GetWarningNotifiesVo>((w, wr, a, wn, cus, system) => new GetWarningNotifiesVo
{
SubSystemId = w.SubSystemId,
SubSystemName = system.CnName,
RuleId = wr.Id,
WarningName = w.Name,
CustomName = cus.Name,
@ -42,13 +44,12 @@ public class WarningQueries : ISugarRepository, IWarningQueries,
ProductCode = wr.ProductCode,
NotifyMode = wn.NotifyMode,
NotifyUser = wn.NotifyUser,
NotifyUserId = wn.NotifyUserId,
FactorTypeSort = w.FactorTypeSort
})
.Mapper(x =>
.Mapper(rule =>
{
x.NotifyModes = x.NotifyMode.Split(',').Select(Enum.Parse<NotifyMode>).ToList();
x.NotifyUserIds = x.NotifyUserId.Split(',').Select(int.Parse).ToList();
rule.NotifyUsers = JsonConvert.DeserializeObject<List<NotifyUserVo>>(rule.NotifyUser) ??
new List<NotifyUserVo>();
})
.ToListAsync();
}

View File

@ -296,7 +296,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
return r.ToIdList();
}
public async Task DeleteTrackAsync(int[] orderIds, List<string> trackCodes)
public async Task<List<int>> DeleteTrackAsync(int[] orderIds, List<string> trackCodes)
{
// var deleteResponse = await Context.DeleteByQueryAsync<TrackDetailsIndex>(d => d
// .Index($"{GlobalConst.TrackDetailsIndex}-*") // 使用通配符匹配所有相关索引
@ -345,6 +345,8 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
{
await DeleteTrackByIdAsync(track.Id, track.IndexName);
}
return tracks.Select(x => x.OrderId).ToList();
}
public async Task DeleteTrackByIdAsync(string id, string indexName)

View File

@ -78,15 +78,11 @@ public class WarningRecordEsRepository : ElasticSearchContextAbstract<WarningRec
.Terms(input.OrderNos))
: null)
&& (input.WarningStatus.HasValue ? q.Term(f => f.WarningStatus, input.WarningStatus) : null)
&& (!input.CustomName.IsNullOrWhiteSpace()
? q.Wildcard(w => w.CustomName, $"*{input.CustomName}*")
: null)
&& (input.CustomId.HasValue ? q.Term(f => f.CustomId, input.CustomId) : null)
&& (!input.WarningName.IsNullOrWhiteSpace()
? q.Wildcard(w => w.WarningName, $"*{input.WarningName}*")
: null)
&& (!input.NotifyUser.IsNullOrWhiteSpace()
? q.Wildcard(w => w.NotifyUser, $"*{input.NotifyUser}*")
: null)
&& (input.NotifyUserId.HasValue ? q.Term(f => f.NotifyUserId, input.NotifyUserId) : null)
&& (input.StartTime.HasValue
? q.DateRange(r => r.Field(f => f.CreateTime).GreaterThanOrEquals(input.StartTime))
: null)
@ -97,6 +93,7 @@ public class WarningRecordEsRepository : ElasticSearchContextAbstract<WarningRec
var data = await Context.SearchAsync<WarningRecordIndex>(x => x
.Index(GlobalConst.TrackWarningRecordIndex)
.Source()
.Query(query)
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))
.From((input.PageIndex - 1) * input.PageSize)
.Size(input.PageSize)

View File

@ -87,7 +87,7 @@ public class WarningRepository : BasicRepository<WarningEntity>, IWarningReposit
.UpdateColumns(x => new
{
x.NotifyMode,
x.NotifyUserId,
x.NotifyUser,
x.UpdateTime,
x.UpdateUserId
})