This commit is contained in:
xiaolipro 2024-09-15 17:13:48 +08:00
parent 4a2b87ba36
commit e0e376404e
11 changed files with 348 additions and 166 deletions

View File

@ -7,9 +7,22 @@ public class WarningDto
/// </summary>
public int TrackStatusId { get; set; }
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomerId { get; set; }
public List<WarningOrderDto> Orders { get; set; } = new();
public override string ToString()
{
return $"子系统:{SubSystemId},客户:{CustomerId},订单:{Orders.Select(x => x.Id)
.JoinAsString(",")},发生轨迹状态{TrackStatusId}";
}
}

View File

@ -2,16 +2,6 @@ namespace SJZY.Track.Application.Contract.Events;
public class TrackChangeAfterUpdateOrderEvent
{
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 订单Id
/// </summary>
@ -32,11 +22,6 @@ public class TrackChangeAfterUpdateOrderEvent
/// </summary>
public string TrackEnContent { get; set; } = null!;
/// <summary>
/// 轨迹状态Id
/// </summary>
public int TrackStatusId { get; set; }
/// <summary>
/// 轨迹发生地
/// </summary>
@ -52,11 +37,6 @@ public class TrackChangeAfterUpdateOrderEvent
/// </summary>
public float TrackTimeZone { get; set; }
/// <summary>
/// 轨迹内容代码
/// </summary>
public string? TrackCode { get; set; }
/// <summary>
/// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种
/// </summary>

View File

@ -0,0 +1,29 @@
namespace SJZY.Track.Application.Contract.Events;
public class TrackWarningCalcEvent
{
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary>
/// 轨迹状态Id
/// </summary>
public int TrackStatusId { get; set; }
/// <summary>
/// 订单id
/// </summary>
public int[] OrderIds { get; set; } = null!;
/// <summary>
/// 轨迹发生时间
/// </summary>
public DateTime TrackTime { get; set; }
}

View File

@ -1,8 +1,6 @@
using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Track.Application.Contract.Dtos.Forewarning;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using Volo.Abp.DependencyInjection;
@ -10,14 +8,11 @@ namespace SJZY.Track.Application.CAP.EventHandlers;
public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICapSubscribe
{
private readonly IForewarningNotifyService _forewarningNotifyService;
private readonly IOrderRepository _orderRepository;
public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository,
IForewarningNotifyService forewarningNotifyService)
public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
_forewarningNotifyService = forewarningNotifyService;
}
[CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)]
@ -27,7 +22,7 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
if (orders.Count == 0)
{
LogHelper.Warn("没有找到订单信息,无法更新轨迹信息");
LogHelper.Warn($"没有找到订单信息:{@event.OrderIds.JoinAsString(",")},无法更新轨迹信息");
return;
}
@ -74,9 +69,6 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
x.LatestTrackTimeZone,
x.DeficiencyTag
});
// 预警计算
await _forewarningNotifyService.WarningCalculateAsync(BuiltWarningDto(orders, @event));
}
private async Task<List<OrderEntity>> GetOrdersAsync(int[] orderIds)
@ -92,41 +84,6 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa
LatestTrackPlace = order.LatestTrackPlace,
LatestTrackTime = order.LatestTrackTime,
LatestTrackTimeZone = order.LatestTrackTimeZone,
// 因素
CargoType = order.CargoType,
CreateTime = order.CreateTime,
ArrivalCountry = order.ArrivalCountry,
ArrivalProvince = order.ArrivalProvince,
ArrivalCity = order.ArrivalCity,
ArrivalPostCode = order.ArrivalPostCode,
IsTransit = order.IsTransit,
LeavePort = order.LeavePort,
ProductCode = order.ProductCode,
});
}
private WarningDto BuiltWarningDto(List<OrderEntity> orders, TrackChangeAfterUpdateOrderEvent @event)
{
return new WarningDto
{
TrackStatusId = @event.TrackStatusId,
SubSystemId = @event.SubSystemId,
CustomerId = @event.CustomId,
Orders = orders.Select(order => new WarningOrderDto
{
Id = order.Id,
TrackTime = @event.TrackTime,
CargoType = order.CargoType,
Month = order.CreateTime.Month,
IsTransit = order.IsTransit,
LeavePort = order.LeavePort,
ProductCode = order.ProductCode,
ArrivalCountry = order.ArrivalCountry,
ArrivalProvince = order.ArrivalProvince,
ArrivalCity = order.ArrivalCity,
ArrivalPostCode = order.ArrivalPostCode,
}).ToList()
};
}
}

View File

@ -4,6 +4,7 @@ using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Dtos.TrackContents;
using SJZY.Track.Domain.Queries;
using Volo.Abp.DependencyInjection;
using OrderIdentifier = SJZY.Track.Application.Contract.Events.OrderIdentifier;
@ -135,12 +136,74 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
return;
}
var insertTracks = await UpsertTrackAsync(@event, canNextOrderIds, trackContent);
if (canNextOrderIds.Count == 0) return;
if (insertTracks.Any())
{
// 批量add to es
await _trackDetailsEsRepository.AddManyAsync(insertTracks);
// 添加轨迹触发订单拉取状态更新
await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(),
@event.TrackCode);
// 添加轨迹触发预警计算(异步)
await _capPublisher.PublishAsync(GlobalConst.TrackWarningCalcSubscribe, new TrackWarningCalcEvent
{
SubSystemId = @event.SubSystemId,
CustomId = @event.CustomId,
OrderIds = canNextOrderIds.ToArray(),
TrackStatusId = trackContent.TrackStatusId,
TrackTime = @event.TrackTime,
});
}
// 触发订单主表更新事件(异步)
await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe,
new TrackChangeAfterUpdateOrderEvent
{
OrderIds = canNextOrderIds.ToArray(),
IsCompleted = trackContent.IsCompleted,
TrackContent = trackContent.TrackContent,
TrackEnContent = trackContent.TrackEnContent,
TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone,
DeficiencyTagValue = @event.DeficiencyTagValue
});
// 触发轨迹推送事件(异步)
var trackPushEvent = new TrackPushEvent
{
OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改,
SubSystemId = @event.SubSystemId,
CustomId = @event.CustomId,
OrderIds = canNextOrderIds.ToArray(),
TrackCode = @event.TrackCode,
SystemPushInfo = new SystemPushStruct
{
TrackStatus = trackContent.TrackStatus,
TrackContent = trackContent.TrackContent,
TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone
}
};
await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent);
}
private async Task<List<TrackDetailsIndex>> UpsertTrackAsync(TrackUpsertEvent @event, List<int> canNextOrderIds,
TrackContentVO trackContent)
{
var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray();
// important:轨迹code相同,时间、发生地不同的,可能存在多条!!
var tracks = await _trackDetailsEsRepository.GetListAsync(orderIds, @event.TrackCode, true);
var insertTracks = new List<TrackDetailsIndex>();
var updateTracks = new List<TrackDetailsIndex>();
foreach (var order in @event.OrderIdentifiers)
{
@ -204,59 +267,17 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser;
track.UpdateTime = DateTime.Now;
await _trackDetailsEsRepository.UpdateAsync(track);
updateTracks.Add(track);
}
canNextOrderIds.Add(order.OrderId);
}
if (canNextOrderIds.Count == 0) return;
if (insertTracks.Any())
if (updateTracks.Any())
{
// 批量add to es
await _trackDetailsEsRepository.AddManyAsync(insertTracks);
// add track触发订单拉取状态更新
await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(),
@event.TrackCode);
await _trackDetailsEsRepository.UpdateManyAsync(updateTracks);
}
// 触发订单主表更新事件(异步)
await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe,
new TrackChangeAfterUpdateOrderEvent
{
SubSystemId = @event.SubSystemId,
CustomId = @event.CustomId,
OrderIds = canNextOrderIds.ToArray(),
IsCompleted = trackContent.IsCompleted,
TrackContent = trackContent.TrackContent,
TrackEnContent = trackContent.TrackEnContent,
TrackStatusId = trackContent.TrackStatusId,
TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone,
TrackCode = @event.TrackCode,
DeficiencyTagValue = @event.DeficiencyTagValue
});
// 触发轨迹推送事件(异步)
var trackPushEvent = new TrackPushEvent
{
OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改,
SubSystemId = @event.SubSystemId,
CustomId = @event.CustomId,
OrderIds = canNextOrderIds.ToArray(),
TrackCode = @event.TrackCode,
SystemPushInfo = new SystemPushStruct
{
TrackStatus = trackContent.TrackStatus,
TrackContent = trackContent.TrackContent,
TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone
}
};
await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent);
return insertTracks;
}
}

View File

@ -0,0 +1,75 @@
using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Track.Application.Contract.Dtos.Forewarning;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.CAP.EventHandlers;
public class TrackWarningCalcEventHandler : ITransientDependency, ICapSubscribe
{
private readonly IForewarningNotifyService _forewarningNotifyService;
private readonly IOrderRepository _orderRepository;
public TrackWarningCalcEventHandler(IOrderRepository orderRepository,
IForewarningNotifyService forewarningNotifyService)
{
_orderRepository = orderRepository;
_forewarningNotifyService = forewarningNotifyService;
}
[CapSubscribe(GlobalConst.TrackWarningCalcSubscribe)]
public async Task ConsumerAsync(TrackWarningCalcEvent @event)
{
var orders = await _orderRepository.GetListAsync(order => @event.OrderIds.Contains(order.Id), order =>
new OrderEntity
{
Id = order.Id,
// 因素
CargoType = order.CargoType,
CreateTime = order.CreateTime,
ArrivalCountry = order.ArrivalCountry,
ArrivalProvince = order.ArrivalProvince,
ArrivalCity = order.ArrivalCity,
ArrivalPostCode = order.ArrivalPostCode,
IsTransit = order.IsTransit,
LeavePort = order.LeavePort,
ProductCode = order.ProductCode,
});
if (orders.Count == 0)
{
LogHelper.Warn($"没有找到订单信息:{@event.OrderIds.JoinAsString(",")},无法做轨迹预警计算");
return;
}
// 预警计算
await _forewarningNotifyService.WarningCalculateAsync(BuiltWarningDto(orders, @event));
}
private WarningDto BuiltWarningDto(List<OrderEntity> orders, TrackWarningCalcEvent @event)
{
return new WarningDto
{
TrackStatusId = @event.TrackStatusId,
SubSystemId = @event.SubSystemId,
CustomerId = @event.CustomId,
Orders = orders.Select(order => new WarningOrderDto
{
Id = order.Id,
TrackTime = @event.TrackTime,
CargoType = order.CargoType,
Month = order.CreateTime.Month,
IsTransit = order.IsTransit,
LeavePort = order.LeavePort,
ProductCode = order.ProductCode,
ArrivalCountry = order.ArrivalCountry,
ArrivalProvince = order.ArrivalProvince,
ArrivalCity = order.ArrivalCity,
ArrivalPostCode = order.ArrivalPostCode,
}).ToList()
};
}
}

View File

@ -89,25 +89,28 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
}
var redisKey = GetForewarningNotifySetKeyRedisKey(dto.SubSystemId);
long addCounter, delCounter = 0;
var tran = RedisHelper.Client.Multi();
// 左区间加入预警队列
await tran.ZAddAsync(redisKey, adds.Select(x =>
// 左区间加入预警队列,【只有第一次发生的才会被加入】
addCounter = await tran.ZAddNxAsync(redisKey, adds.Select(x =>
{
var entry = new WarningNotifyCacheEntry(x.ruleId, x.orderId, x.counter);
return new ZMember(entry.ToString(), x.ts);
}).ToArray());
// 右区间移出预警队列
// 右区间移出预警队列,【只要发生了就移除】
var right = dels.Select(x => new WarningNotifyCacheEntry(x.ruleId, x.orderId, x.counter)).ToList();
if (!right.IsNullOrEmpty())
{
await tran.ZRemAsync(redisKey, right.Select(x => x.ToString()).ToArray());
delCounter = await tran.ZRemAsync(redisKey, right.Select(x => x.ToString()).ToArray());
}
tran.Exec();
LogHelper.Info($"本次共计产生{addCounter}条预警,移除{delCounter}条预警,触发缘由是");
await _warningRecordEsRepository.BulkUpdateAsync(dels); // 标记处理完成
}
@ -127,21 +130,21 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
var ruleIds = entries.Select(x => x.RuleId).Distinct().ToList();
var notifyRules = await _warningQueries.GetWarningNotifyRulesAsync(ruleIds);
var userRules = new Dictionary<int, List<GetWarningNotifiesVo>>();
foreach (var rule in notifyRules)
{
foreach (var userId in rule.NotifyUserIds)
{
if (!userRules.ContainsKey(userId))
{
userRules[userId] = new List<GetWarningNotifiesVo>();
}
userRules[userId].Add(rule);
}
}
// 写入es预警记录
var warningRecords = await WriteWarningRecordAsync(entries, notifyRules);
// 发通知
await SendCoreAsync(entries, notifyRules);
// 移除已处理的预警
await RedisHelper.Client.ZRemRangeByScoreAsync(redisKey, 0, timestamp);
return warningRecords.Count;
}
private async Task<List<WarningRecordIndex>> WriteWarningRecordAsync(List<WarningNotifyCacheEntry> entries,
List<GetWarningNotifiesVo> notifyRules)
{
var warningRecords = new List<WarningRecordIndex>();
foreach (var entry in entries)
{
@ -163,9 +166,25 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
}
await _warningRecordEsRepository.BulkInsertAsync(warningRecords);
return warningRecords;
}
private Task SendCoreAsync(List<WarningNotifyCacheEntry> entries, List<GetWarningNotifiesVo> notifyRules)
{
var userRules = new Dictionary<int, List<GetWarningNotifiesVo>>();
foreach (var rule in notifyRules)
{
foreach (var userId in rule.NotifyUserIds)
{
if (!userRules.ContainsKey(userId))
{
userRules[userId] = new List<GetWarningNotifiesVo>();
}
userRules[userId].Add(rule);
}
}
// 发通知
foreach (var userRule in userRules)
{
var siteInternalContent = BuildNotifyContent(userRule.Value, entries, NotifyMode.SiteInternal);
@ -173,48 +192,62 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
if (!string.IsNullOrEmpty(siteInternalContent))
{
// todo:发送站内通知
_ = _requestSendMessageService.Service.SendMessageByEmptyTemplateAsync(
new SendMessageByEmptyTemplateInput
_ = Task.Run(async () =>
{
// todo:发送站内通知
var res = await _requestSendMessageService.Service.SendMessageByEmptyTemplateAsync(
new SendMessageByEmptyTemplateInput
{
IsNeedToHandle = null,
BizId = null,
MsgSource = null,
SystemId = 0,
TemplateCode = null,
Channels = null,
MsgTitle = null,
MsgContent = null,
PcURl = null,
MobileURl = null,
FileUrl = null,
fileName = null,
receivers = null,
SiteLetterComponentStyle = (ComponentStyle) 0
});
if (res.Code != GlobalConst.SuccessCode)
{
IsNeedToHandle = null,
BizId = null,
MsgSource = null,
SystemId = 0,
TemplateCode = null,
Channels = null,
MsgTitle = null,
MsgContent = null,
PcURl = null,
MobileURl = null,
FileUrl = null,
fileName = null,
receivers = null,
SiteLetterComponentStyle = (ComponentStyle) 0
});
LogHelper.Error($"发送站内通知失败,用户:{userRule.Key},内容:{siteInternalContent}");
}
});
}
if (!string.IsNullOrEmpty(feiShuContent))
{
// 发送飞书通知
_ = _messageClient.SendMessageAsync(new SendMessageInput
_ = Task.Run(async () =>
{
AppId = null,
AppSecret = null,
ReceiveIdType = IdTypeEnums.user_id,
MsgType = MsgTypeEnums.文本,
ReceiveIds = new List<string>
// 发送飞书通知
var res = await _messageClient.SendMessageAsync(new SendMessageInput
{
userRule.Key.ToString()
},
Content = feiShuContent
AppId = null,
AppSecret = null,
ReceiveIdType = IdTypeEnums.user_id,
MsgType = MsgTypeEnums.文本,
ReceiveIds = new List<string>
{
userRule.Key.ToString()
},
Content = feiShuContent
});
if (res.Code != GlobalConst.SuccessCode)
{
LogHelper.Error($"发送飞书通知失败,用户:{userRule.Key},内容:{feiShuContent}");
}
});
}
}
await RedisHelper.Client.ZRemRangeByScoreAsync(redisKey, 0, timestamp);
return warningRecords.Count;
return Task.CompletedTask;
}
private string GetForewarningNotifySetKeyRedisKey(int subSystemId) =>
@ -259,6 +292,7 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
var res = new List<ForewarningRuleCacheEntry>();
foreach (var rule in rules)
{
// 规则至少有一个因素,如果订单任一因素不符合则不命中
if (rule.IsTransit != null)
{
if (order.IsTransit != rule.IsTransit) continue;
@ -287,7 +321,8 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
if (!rule.Areas.IsNullOrEmpty())
{
var inArea = false;
foreach (var area in rule.Areas!.Where(area => order.ArrivalCountry == area.Country))
var areas = rule.Areas!.Where(area => order.ArrivalCountry == area.Country).ToList();
foreach (var area in areas)
{
if (!area.LeftPostcode.IsNullOrEmpty() && !area.RightPostcode.IsNullOrEmpty())
{
@ -296,12 +331,31 @@ public class ForewarningNotifyService : IForewarningNotifyService, ITransientDep
string.CompareOrdinal(order.ArrivalPostCode, area.RightPostcode) > 0) continue;
}
if (!area.City.IsNullOrEmpty() && order.ArrivalCity != area.City) continue;
if (!area.Province.IsNullOrEmpty() && order.ArrivalProvince != area.Province) continue;
inArea = true;
break;
}
if (!inArea)
{
foreach (var area in areas)
{
if (!area.City.IsNullOrEmpty() && order.ArrivalCity != area.City) continue;
inArea = true;
break;
}
}
if (!inArea)
{
foreach (var area in areas)
{
if (!area.Province.IsNullOrEmpty() && order.ArrivalProvince != area.Province) continue;
inArea = true;
break;
}
}
if (!inArea) continue;
}

View File

@ -14,6 +14,8 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
Task UpdateAsync(TrackDetailsIndex index);
Task UpdateManyAsync(List<TrackDetailsIndex> indexes, int maxRetries = 3);
Task AddManyAsync(List<TrackDetailsIndex> index);
Task AddAsync(TrackDetailsIndex track);

View File

@ -50,5 +50,5 @@ public partial class GlobalConst
/// <summary>
/// 预警计算任务
/// </summary>
public const string TrackWarningCalc = "SJZY.Track.TrackWarningCalc";
public const string TrackWarningCalcSubscribe = "SJZY.Track.TrackWarningCalc";
}

View File

@ -154,6 +154,57 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
}
}
public async Task UpdateManyAsync(List<TrackDetailsIndex> indexes, int maxRetries = 3)
{
var retryCount = 0;
var updateSuccessful = false;
var track = indexes.First();
while (retryCount < maxRetries && !updateSuccessful)
{
var response = await Context.UpdateByQueryAsync<TrackDetailsIndex>(u => u
.Index(GlobalConst.TrackDetailsIndex)
.Query(q => q
.Ids(t => t.Values(indexes.Select(x => x.Id)))
)
.Script(s => s
.Source(@"
ctx._source.TrackPlace = params.trackPlace;
ctx._source.TrackTime = params.trackTime;
ctx._source.TrackTimeZone = params.trackTimeZone;
ctx._source.UpdateUser = params.updateUser;
ctx._source.UpdateTime = params.updateTime;
")
.Params(p => p
.Add("trackPlace", track.TrackPlace)
.Add("trackTime", track.TrackTime)
.Add("trackTimeZone", track.TrackTimeZone)
.Add("updateUser", track.UpdateUser)
.Add("updateTime", DateTime.Now)
)
)
);
if (response.IsValid)
{
updateSuccessful = true;
}
else if (response.ServerError?.Status == 409) // 409 表示版本冲突
{
retryCount++;
if (retryCount >= maxRetries)
{
throw new InvalidOperationException(
$"轨迹更新冲突达到最大次数,track:{indexes.Count}条,原因:{response.DebugInformation}。");
}
}
else
{
throw new InvalidOperationException($"轨迹更新失败,track:{indexes.Count}条,原因:{response.DebugInformation}。");
}
}
}
public async Task AddManyAsync(List<TrackDetailsIndex> tracks)
{
// 按天写入es

View File

@ -49,7 +49,7 @@ public class WarningRecordEsRepository : ElasticSearchContextAbstract<WarningRec
foreach (var rule in rules)
{
var r = await Context.UpdateByQueryAsync<WarningRecordIndex>(u => u
.Index($"{GlobalConst.TrackWarningRecordIndex}-*")
.Index(GlobalConst.TrackWarningRecordIndex)
.Query(q =>
q.Term(f => f.RuleId, rule.ruleId)
&& q.Term(f => f.OrderId, rule.orderId)