feat:暂存轨迹priority

This commit is contained in:
xiaolipro 2025-11-25 18:05:40 +08:00
parent ad3bf02ccd
commit 3add96f52f
25 changed files with 860 additions and 109 deletions

View File

@ -24,6 +24,8 @@ public class TrackPullAutoMapperProfile : Profile
CreateMap<GetTrackPullContentListCacheVO, TrackPullContentConfigDto>(MemberList.None);
CreateMap<EditTrackPullPriorityInput, TrackPullPriorityEntity>(MemberList.None);
CreateMap<PullConfigInfo, UpdateOrderPullConfigsInputVo>(MemberList.None);
}
}

View File

@ -1,3 +1,5 @@
using TrackCenter.Domain.Aggregates.OrderAggregate;
namespace TrackCenter.Application.Dtos.TrackPull;
public class EditTrackPullConfigInput
@ -12,17 +14,12 @@ public class EditTrackPullConfigInput
/// <summary>
/// 应用
/// </summary>
public string? AppKey { get; set; }
public string AppKey { get; set; }
/// <summary>
/// 服务商id
/// 服务商code
/// </summary>
public int? ServiceProviderId { get; set; }
/// <summary>
/// 服务商拉取频率(分钟)
/// </summary>
public int PullInterval { get; set; }
public string ServiceProviderCode { get; set; }
/// <summary>
/// 解析方式,1取接口通返参映射后的,2取服务商原返参
@ -78,4 +75,34 @@ public class EditTrackPullConfigInput
/// 轨迹时区参数名
/// </summary>
public string? TrackTimeZoneName { get; set; }
/// <summary>
/// 客户
/// </summary>
public string? Customer { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public TrackOrderType OrderType { get; set; }
/// <summary>
/// 开始轨迹code
/// </summary>
public string? StartTrackCode { get; set; }
/// <summary>
/// 结束轨迹code
/// </summary>
public string? EndTrackCode { get; set; }
/// <summary>
/// 开始前的静默(小时)
/// </summary>
public int SilenceBeforeStart { get; set; }
/// <summary>
/// 结束后的静默(小时)
/// </summary>
public int SilenceAfterEnd { get; set; }
}

View File

@ -0,0 +1,38 @@
using TrackCenter.Domain.Aggregates.TrackPullAggregate;
namespace TrackCenter.Application.Dtos.TrackPull;
public class EditTrackPullPriorityInput
{
/// <summary>
/// 操作类型
/// </summary>
public OptionTypeNoNull Options { get; set; }
public int? Id { get; set; }
/// <summary>
/// 轨迹拉取配置id
/// </summary>
public int? TrackPullConfigId { get; set; }
/// <summary>
/// 客户
/// </summary>
public string? Customer { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public TrackOrderType? OrderType { get; set; }
/// <summary>
/// 优先级
/// </summary>
public string? Priority { get; set; }
/// <summary>
/// 服务商拉取频率(分钟)
/// </summary>
public int? PullInterval { get; set; }
}

View File

@ -1,3 +1,5 @@
using TrackCenter.Domain.Aggregates.OrderAggregate;
namespace TrackCenter.Application.Dtos.TrackPull;
public class TrackPullParamConfigDto
@ -66,4 +68,24 @@ public class TrackPullParamConfigDto
/// 轨迹内容代码
/// </summary>
public string? TrackContentCode { get; set; }
/// <summary>
/// 开始轨迹code
/// </summary>
public string StartTrackCode { get; set; } = null!;
/// <summary>
/// 结束轨迹code
/// </summary>
public string EndTrackCode { get; set; } = null!;
/// <summary>
/// 开始前的静默(小时)
/// </summary>
public int SilenceBeforeStart { get; set; }
/// <summary>
/// 结束后的静默(小时)
/// </summary>
public int SilenceAfterEnd { get; set; }
}

View File

@ -5,4 +5,29 @@ public class TrackPullParamsWithContentDto
public TrackPullParamConfigDto ParamConfig { get; set; } = new();
public List<TrackPullContentConfigDto> ContentConfigs { get; set; } = new();
//public List<TrackPullPriorityDto> Priorities { get; set; } = new();
}
public class TrackPullPriorityDto
{
/// <summary>
/// 客户
/// </summary>
public string? Customer { get; set; }
/// <summary>
/// 渠道
/// </summary>
public string? Channel { get; set; }
/// <summary>
/// 产品
/// </summary>
public string? Product { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public TrackOrderType OrderType { get; set; }
}

View File

@ -229,18 +229,4 @@ public class ProvideQueries : SqlSugarRootlessRepository<TrackCenterDbContext>,
content.IsToMq = content.TrackFlags.Any(x => x.IsToMq);
}
}
public async Task<List<TrackPullConfigVo>> GetAllPullConfigsAsync()
{
return await Context.Queryable<TrackPullConfigEntity>()
.LeftJoin<VServiceProviderEntity>((a, b) => a.ServiceProviderId == b.Id)
.Select((a, b) => new TrackPullConfigVo
{
PullInterval = a.PullInterval,
ServiceProviderId = a.ServiceProviderId,
ServiceProviderCode = b.Code,
AppKey = a.AppKey
})
.ToListAsync();
}
}

View File

@ -80,9 +80,18 @@ public class TrackRefreshEventHandler : ITransientDependency, IRabbitHandler
return;
}
// 最优先级,最匹配的 权重 sort
// 客户、渠道、产品
// */*/* 全部
// 客户A/渠道A/产品A
// 客户A
// 客户A 渠道B 产品A
var config = await _trackPullCacheService.GetPullParamsWithContentAsync(attach.AppKey,
attach.ServiceProviderCode);
if (config == null)
if (config is null)
{
_logger.LogWarning("请求id: {@RequestId},轨迹消费失败,找不到拉取配置:{@Attach}", attach.ToJson(), @event.RequestId);
return;

View File

@ -36,7 +36,7 @@ public partial class OrderService : ApplicationServiceBase
}
/// <summary>
/// 新增、更新订单(存在就更新)
/// 新增、更新小包(存在就更新)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>

View File

@ -0,0 +1,275 @@
using System.ComponentModel.DataAnnotations;
using InterfaceForward.Domain.Shared.Helpers;
using TrackCenter.Domain.Aggregates.OrderAggregate;
using TrackCenter.Domain.Aggregates.TrackPullAggregate;
using TrackCenter.Repository.Aggregates.OrderAggregate;
namespace TrackCenter.Application.Services.ProvideServices;
public class OrderServiceV2(
IOrderRepository orderRepository,
IOrderOperationRecordEsRepository orderOperationRecordEsRepository,
ITrackPullConfigRepository trackPullConfigRepository)
: ApplicationServiceBase
{
/// <summary>
/// 新增、更新小包(存在就更新)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("OrderV2/UpsertSmallBag")]
public async Task<IdBaseDto> UpsertAsync(UpsertSmallBagInput input)
{
// 校验订单是否已存在,存在则更新
var order = await orderRepository.GetFirstAsync(x =>
x.AppKey == input.ApiCode && x.OrderType == TrackOrderType.小包 && x.OrderNo == input.OrderNo);
// 订单已存在则视为更新
if (order != null)
{
order = await BuiltOrder(input);
await orderRepository.UpdateOrderAsync(order);
var index = new OrderOperationRecordIndex
{
OrderId = order.Id,
OrderNo = input.OrderNo,
OptionType = OrderOperationType.修改订单.ToString(),
Content = input.ToJson(),
CreateUserId = CurrentUserId,
CreateUserName = CurrentUser.UserName ?? string.Empty,
};
_ = orderOperationRecordEsRepository.AddAsync(index);
return new IdBaseDto
{
Id = order.Id
};
}
order = await BuiltOrder(input);
var orderId = await orderRepository.CreateOrderAsync(order);
// 写入操作日志
var indexForAdd = new OrderOperationRecordIndex
{
OrderId = orderId,
OrderNo = input.OrderNo,
OptionType = nameof(OrderOperationType.创建订单),
Content = input.ToJson(),
CreateUserId = CurrentUserId,
CreateUserName = CurrentUser.UserName ?? string.Empty,
CreateTime = DateTime.Now
};
_ = orderOperationRecordEsRepository.AddAsync(indexForAdd);
return new IdBaseDto
{
Id = orderId
};
}
private async Task<OrderEntity> BuiltOrder(UpsertSmallBagInput input)
{
var order = new OrderEntity
{
AppKey = input.ApiCode,
OrderType = TrackOrderType.小包,
OrderNo = input.OrderNo,
TrackNo = input.TrackNo,
ThirdPartyOrderNumber = input.OtherNo,
Customer = input.Client,
Channel = input.Channel,
ProductCode = input.Product,
ArrivalCountry = input.Consignee.CountryCode,
ArrivalProvince = input.Consignee.Province,
ArrivalPostCode = input.Consignee.Postcode,
ArrivalCity = input.Consignee.City,
ArrivalEmail = input.Consignee.Email,
};
var config = await trackPullConfigRepository
.GetListAsync(x => x.AppKey == input.ApiCode
&& x.ServiceProviderCode == input.ApiCode && x.OrderType == TrackOrderType.小包);
order.OrderPullStatus = BuiltOrderPullStatus(config, order);
return order;
}
private static List<OrderPullStatusEntity> BuiltOrderPullStatus(
List<TrackPullConfigEntity> configs,
OrderEntity order)
{
if (configs.IsNullOrEmpty()) return [];
TrackPullConfigEntity? selected = null;
var bestScore = -1;
foreach (var config in configs)
{
if (!IsConfigApplicable(config, order))
{
continue;
}
var score = CalculateMatchScore(config, order);
if (score > bestScore)
{
bestScore = score;
selected = config;
}
}
if (selected == null) throw new BusinessException(message: "没有一个拉取配置可以适用,请配置,否则无法拉取轨迹");
return [CreateOrderPullStatus(selected, order)];
}
private static bool IsConfigApplicable(TrackPullConfigEntity config, OrderEntity order)
{
return IsFieldApplicable(order.Customer, config.Customer) &&
IsFieldApplicable(order.Channel, config.Channel) &&
IsFieldApplicable(order.ProductCode, config.Product);
}
private static bool IsFieldApplicable(string? orderValue, string? configValue)
{
if (string.IsNullOrWhiteSpace(configValue))
{
return true;
}
return string.Equals(configValue, orderValue, StringComparison.OrdinalIgnoreCase);
}
private static int CalculateMatchScore(TrackPullConfigEntity config, OrderEntity order)
{
var score = 0;
if (IsPreciseMatch(order.Customer, config.Customer))
{
score++;
}
if (IsPreciseMatch(order.Channel, config.Channel))
{
score++;
}
if (IsPreciseMatch(order.ProductCode, config.Product))
{
score++;
}
return score;
}
private static bool IsPreciseMatch(string? orderValue, string? configValue)
{
return !string.IsNullOrWhiteSpace(configValue) &&
string.Equals(configValue, orderValue, StringComparison.OrdinalIgnoreCase);
}
private static OrderPullStatusEntity CreateOrderPullStatus(TrackPullConfigEntity config, OrderEntity order)
{
var status = new OrderPullStatusEntity
{
ServiceProviderCode = config.ServiceProviderCode,
OrderNo = order.OrderNo,
PullStatus = TrackPullStatus.Init,
StartTrackCode = config.StartTrackCode,
EndTrackCode = config.EndTrackCode,
SilenceBeforeStart = config.SilenceBeforeStart,
SilenceAfterEnd = config.SilenceAfterEnd,
StartTime = GlobalConst.MaxDateTime,
EndTime = GlobalConst.MaxDateTime
};
if (string.IsNullOrWhiteSpace(config.StartTrackCode))
{
status.PullStatus = TrackPullStatus.SilenceBeforeStart;
status.StartTime = DateTime.Now.AddHours(config.SilenceBeforeStart);
}
return status;
}
}
public class UpsertSmallBagInput
{
/// <summary>
/// 客户名称,或者code,必填
/// </summary>
[Required]
public string Client { get; set; }
/// <summary>
/// 客户单号,必填
/// </summary>
[Required]
public string OrderNo { get; set; }
/// <summary>
/// 尾程单号,必填
/// </summary>
[Required]
public string TrackNo { get; set; }
/// <summary>
/// 其他单号
/// </summary>
public string OtherNo { get; set; }
/// <summary>
/// 渠道名称,或者code
/// </summary>
public string Channel { get; set; }
/// <summary>
/// 产品名称,或者code
/// </summary>
public string Product { get; set; }
/// <summary>
/// 服务商code
/// </summary>
public string ApiCode { get; set; }
/// <summary>
/// 收件人信息
/// </summary>
public Consignee Consignee { get; set; }
}
public class Consignee
{
/// <summary>
/// 收件人国家,必填
/// </summary>
[Required]
public string CountryCode { get; set; }
/// <summary>
/// 收件人州省
/// </summary>
public string Province { get; set; }
/// <summary>
/// 收件人邮编
/// </summary>
public string Postcode { get; set; }
/// <summary>
/// 收件人城市
/// </summary>
public string City { get; set; }
/// <summary>
/// 收件人邮箱
/// </summary>
public string Email { get; set; }
}

View File

@ -7,6 +7,7 @@ using TrackCenter.Application.Options;
using TrackCenter.Application.Queries;
using TrackCenter.Application.Services.TrackPull;
using TrackCenter.Application.Track2InterfaceRelay;
using TrackCenter.Domain.Aggregates.TrackPullAggregate;
using TrackCenter.Domain.Dtos.TrackPull;
namespace TrackCenter.Application.Services.TimerTaskss;
@ -34,8 +35,14 @@ public class TrackPullTask : ApplicationServiceBase, ISingletonDependency
{
using var serviceScope = _serviceScopeFactory.CreateScope();
var provideQueries = serviceScope.ServiceProvider.GetRequiredService<ProvideQueries>();
var configs = await provideQueries.GetAllPullConfigsAsync();
var trackPullConfigRepository = serviceScope.ServiceProvider.GetRequiredService<ITrackPullConfigRepository>();
var configs = await trackPullConfigRepository.GetListAsync(x => true, x => new TrackPullConfigVo
{
// todo:去读priority表,按照客户、订单类型、优先级拉
PullInterval = 60,
ServiceProviderCode = x.ServiceProviderCode,
AppKey = x.AppKey
});
foreach (var config in configs)
{

View File

@ -8,7 +8,6 @@ using TrackCenter.Domain.Dtos.TrackPull;
using SqlSugar;
using TrackCenter.Application.Helpers;
using TrackCenter.Application.Options;
using TrackCenter.Repository;
namespace TrackCenter.Application.Services.TrackPull;
@ -17,21 +16,12 @@ namespace TrackCenter.Application.Services.TrackPull;
/// </summary>
[ApiExplorerSettings(GroupName = "轨迹拉取")]
[Route("/Track/PullConfig")]
public class TrackPullService : ApplicationServiceBase
public class TrackPullService(
ITrackPullConfigRepository trackPullConfigRepository,
TrackPullCacheService trackPullCacheService,
IOptionsMonitor<InterfaceRelayParamsConfigOptions> options)
: ApplicationServiceBase
{
private readonly IOptionsMonitor<InterfaceRelayParamsConfigOptions> _options;
private readonly TrackPullCacheService _trackPullCacheService;
private readonly ITrackPullConfigRepository _trackPullConfigRepository;
public TrackPullService(
ITrackPullConfigRepository trackPullConfigRepository,
TrackPullCacheService trackPullCacheService, IOptionsMonitor<InterfaceRelayParamsConfigOptions> options)
{
_trackPullConfigRepository = trackPullConfigRepository;
_trackPullCacheService = trackPullCacheService;
_options = options;
}
/// <summary>
/// 轨迹拉取配置列表
/// </summary>
@ -40,7 +30,7 @@ public class TrackPullService : ApplicationServiceBase
[HttpPost("GetPage")]
public async Task<PagedResult<GetTrackPullConfigPageOutputVO>> GetPageAsync([FromBody] KeywordsInputVO input)
{
return await _trackPullConfigRepository.GetPageAsync(input);
return await trackPullConfigRepository.GetPageAsync(input);
}
/// <summary>
@ -52,7 +42,7 @@ public class TrackPullService : ApplicationServiceBase
public async Task<PagedResult<GetTrackPullContentPageOutputVO>> GetContentPageAsync(
[FromBody] GetTrackPullContentPageInputVO input)
{
return await _trackPullConfigRepository.GetContentPageAsync(input);
return await trackPullConfigRepository.GetContentPageAsync(input);
}
/// <summary>
@ -63,7 +53,7 @@ public class TrackPullService : ApplicationServiceBase
[HttpGet("GetDetail")]
public async Task<GetTrackPullConfigDetailOutputVO> GetDetailAsync(int id)
{
var res = await _trackPullConfigRepository.GetDetailAsync(id);
var res = await trackPullConfigRepository.GetDetailAsync(id);
if (res == null)
{
@ -81,7 +71,7 @@ public class TrackPullService : ApplicationServiceBase
[HttpGet("GetContentDetail")]
public async Task<GetTrackPullContentDetailOutputVO> GetContentDetailAsync(int id)
{
return await _trackPullConfigRepository.GetContentDetailAsync(id);
return await trackPullConfigRepository.GetContentDetailAsync(id);
}
/// <summary>
@ -92,15 +82,17 @@ public class TrackPullService : ApplicationServiceBase
[HttpPost("Edit")]
public async Task<bool> EditAsync([FromBody] EditTrackPullConfigInput input)
{
if (input.PullInterval < 60) input.PullInterval = 60;
//if (input.PullInterval < 60) input.PullInterval = 60;
if (input.Options != OptionTypeNoNull.删除)
{
Expression<Func<TrackPullConfigEntity, bool>> isAnyExp = x =>
x.AppKey == input.AppKey && x.ServiceProviderId == input.ServiceProviderId;
x.AppKey == input.AppKey &&
x.ServiceProviderCode == input.ServiceProviderCode &&
x.OrderType == input.OrderType;
if (input.Options == OptionTypeNoNull.修改) isAnyExp = isAnyExp.And(x => x.Id != input.Id);
if (await _trackPullConfigRepository.IsAnyAsync(isAnyExp))
if (await trackPullConfigRepository.IsAnyAsync(isAnyExp))
throw new BusinessException("配置已经存在");
}
@ -112,7 +104,7 @@ public class TrackPullService : ApplicationServiceBase
if (input.ParseMethod == (int) ParseMethod.InterfaceRelay)
{
var paramsConfig = _options.CurrentValue;
var paramsConfig = options.CurrentValue;
if (paramsConfig == null)
{
throw new BusinessException(message: "未找到接口通参数配置,联系管理员添加");
@ -130,21 +122,21 @@ public class TrackPullService : ApplicationServiceBase
trackPullEntity.TrackTimeZoneName = paramsConfig.TrackTimeZoneName;
}
var id = await _trackPullConfigRepository.InsertReturnIdentityAsync(trackPullEntity);
var id = await trackPullConfigRepository.InsertReturnIdentityAsync(trackPullEntity);
await _trackPullCacheService.SetPullConfigAsync(id);
await trackPullCacheService.SetPullConfigAsync(id);
}
break;
case OptionTypeNoNull.修改:
{
var oldTrackPullEntity = await _trackPullConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
var oldTrackPullEntity = await trackPullConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
throw new BusinessException("配置不存在");
ObjectMapper.Map(input, oldTrackPullEntity);
if (input.ParseMethod == (int) ParseMethod.InterfaceRelay)
{
var paramsConfig = _options.CurrentValue;
var paramsConfig = options.CurrentValue;
if (paramsConfig == null)
{
throw new BusinessException(message: "未找到接口通参数配置,联系管理员添加");
@ -162,20 +154,20 @@ public class TrackPullService : ApplicationServiceBase
oldTrackPullEntity.TrackTimeZoneName = paramsConfig.TrackTimeZoneName;
}
await _trackPullConfigRepository.UpdateAsync(oldTrackPullEntity);
await trackPullConfigRepository.UpdateAsync(oldTrackPullEntity);
await _trackPullCacheService.SetPullConfigAsync(input.Id!.Value);
await trackPullCacheService.SetPullConfigAsync(input.Id!.Value);
}
break;
case OptionTypeNoNull.删除:
using (var ts = TransacationHelper.GetReadCommitted())
{
await _trackPullConfigRepository.SoftDeleteAsync(x => x.Id == input.Id);
await trackPullConfigRepository.SoftDeleteAsync(x => x.Id == input.Id);
await _trackPullConfigRepository.SoftDeleteContentAsync(x => x.TrackPullConfigId == input.Id);
await trackPullConfigRepository.SoftDeleteContentAsync(x => x.TrackPullConfigId == input.Id);
await _trackPullCacheService.SetPullConfigAsync(input.Id!.Value);
await trackPullCacheService.SetPullConfigAsync(input.Id!.Value);
ts.Complete();
}
@ -206,7 +198,7 @@ public class TrackPullService : ApplicationServiceBase
isContentAnyExp = isContentAnyExp.And(x => x.Id != input.Id);
}
if (await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x =>
if (await trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x =>
x.TrackContentId == input.TrackContentId)))
throw new BusinessException("配置已存在");
@ -218,7 +210,7 @@ public class TrackPullService : ApplicationServiceBase
trackStatusValuesExp = trackStatusValuesExp.Or(x => SqlFunc.SplitIn(x.TrackStatusValue, item));
});
if (await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(trackStatusValuesExp)))
if (await trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(trackStatusValuesExp)))
throw new BusinessException(message: "配置已存在");
}
@ -230,7 +222,7 @@ public class TrackPullService : ApplicationServiceBase
trackKeywordExp = trackKeywordExp.Or(x => SqlFunc.SplitIn(x.TrackKeyword, item));
});
if (await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(trackKeywordExp)))
if (await trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(trackKeywordExp)))
throw new BusinessException(message: "配置已存在");
}
}
@ -241,8 +233,8 @@ public class TrackPullService : ApplicationServiceBase
{
var entity = ObjectMapper.Map<EditTrackPullContentInput, TrackPullContentConfigEntity>(input);
await _trackPullConfigRepository.InsertContentAsync(entity);
await _trackPullCacheService.SetPullConfigAsync(input.TrackPullConfigId!.Value);
await trackPullConfigRepository.InsertContentAsync(entity);
await trackPullCacheService.SetPullConfigAsync(input.TrackPullConfigId!.Value);
break;
}
@ -250,13 +242,13 @@ public class TrackPullService : ApplicationServiceBase
case OptionTypeNoNull.修改:
{
var oldTrackPullContentEntity =
await _trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
await trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: "找不到数据");
ObjectMapper.Map(input, oldTrackPullContentEntity);
await _trackPullConfigRepository.UpdateContentAsync(oldTrackPullContentEntity);
await _trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId);
await trackPullConfigRepository.UpdateContentAsync(oldTrackPullContentEntity);
await trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId);
break;
}
@ -264,11 +256,100 @@ public class TrackPullService : ApplicationServiceBase
case OptionTypeNoNull.删除:
{
var oldTrackPullContentEntity =
await _trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
await trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: "找不到数据");
await _trackPullConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id);
await _trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId);
await trackPullConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id);
await trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId);
break;
}
default:
throw new ArgumentOutOfRangeException();
}
return true;
}
/// <summary>
/// 轨迹拉取优先级配置列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPriorityPage")]
public async Task<PagedResult<GetTrackPullPriorityPageOutputVO>> GetPriorityPageAsync(
[FromBody] GetTrackPullPriorityPageInputVO input)
{
return await trackPullConfigRepository.GetPriorityPageAsync(input);
}
/// <summary>
/// 轨迹拉取优先级配置详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("GetPriorityDetail")]
public async Task<GetTrackPullPriorityDetailOutputVO> GetPriorityDetailAsync(int id)
{
return await trackPullConfigRepository.GetPriorityDetailAsync(id);
}
/// <summary>
/// 轨迹拉取优先级配置编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditPriority")]
public async Task<bool> EditPriorityAsync([FromBody] EditTrackPullPriorityInput input)
{
if (input.Options != OptionTypeNoNull.删除)
{
Expression<Func<TrackPullPriorityEntity, bool>> isPriorityAnyExp = x =>
x.TrackPullConfigId == input.TrackPullConfigId &&
x.Customer == input.Customer &&
x.OrderType == input.OrderType;
if (input.Options == OptionTypeNoNull.修改)
{
isPriorityAnyExp = isPriorityAnyExp.And(x => x.Id != input.Id);
}
if (await trackPullConfigRepository.IsPriorityAnyAsync(isPriorityAnyExp))
throw new BusinessException("配置已存在");
}
switch (input.Options)
{
case OptionTypeNoNull.新增:
{
var entity = ObjectMapper.Map<EditTrackPullPriorityInput, TrackPullPriorityEntity>(input);
await trackPullConfigRepository.InsertPriorityAsync(entity);
break;
}
case OptionTypeNoNull.修改:
{
var oldTrackPullPriorityEntity =
await trackPullConfigRepository.GetPriorityByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: "找不到数据");
ObjectMapper.Map(input, oldTrackPullPriorityEntity);
await trackPullConfigRepository.UpdatePriorityAsync(oldTrackPullPriorityEntity);
break;
}
case OptionTypeNoNull.删除:
{
var oldTrackPullPriorityEntity =
await trackPullConfigRepository.GetPriorityByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: "找不到数据");
await trackPullConfigRepository.SoftDeletePriorityAsync(x => x.Id == input.Id);
break;
}

View File

@ -21,6 +21,12 @@ public class OrderEntity : FullAuditedAggregateRoot<int, int>
[SugarColumn(ColumnName = "OrderNo")]
public string OrderNo { get; set; } = null!;
/// <summary>
/// 尾程单号
/// </summary>
[SugarColumn(ColumnName = "TrackNo")]
public string TrackNo { get; set; } = null!;
/// <summary>
/// 订单类型(主数据枚举TrackOrderType)
/// </summary>
@ -117,6 +123,12 @@ public class OrderEntity : FullAuditedAggregateRoot<int, int>
[SugarColumn(ColumnName = "ArrivalPort")]
public string? ArrivalPort { get; set; }
/// <summary>
/// 邮箱
/// </summary>
[SugarColumn(ColumnName = "ArrivalEmail")]
public string? ArrivalEmail { get; set; }
/// <summary>
/// 起运城市
/// </summary>
@ -195,11 +207,21 @@ public class OrderEntity : FullAuditedAggregateRoot<int, int>
[SugarColumn(ColumnName = "ThirdPartyOrderNumber")]
public string? ThirdPartyOrderNumber { get; set; }
[SugarColumn(IsIgnore = true)]
public List<OrderFlightEntity> OrderFlights { get; set; }
/// <summary>
/// 服务渠道
/// </summary>
[SugarColumn(ColumnName = "Channel")]
public string? Channel { get; set; }
[SugarColumn(IsIgnore = true)]
public List<OrderPullStatusEntity> OrderPullStatus { get; set; }
/// <summary>
/// 服务商代码
/// </summary>
[SugarColumn(ColumnName = "ServiceProviderCode")]
public string? ServiceProviderCode { get; set; }
[SugarColumn(IsIgnore = true)] public List<OrderFlightEntity> OrderFlights { get; set; } = [];
[SugarColumn(IsIgnore = true)] public List<OrderPullStatusEntity> OrderPullStatus { get; set; } = [];
public void ResetTrackInfo()
{

View File

@ -41,14 +41,39 @@ public interface ITrackPullConfigRepository : IBasicRepository<TrackPullConfigEn
/// <returns></returns>
Task<GetTrackPullContentDetailOutputVO> GetContentDetailAsync(int id);
/// <summary>
/// 轨迹拉取优先级配置列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<PagedResult<GetTrackPullPriorityPageOutputVO>> GetPriorityPageAsync(GetTrackPullPriorityPageInputVO input);
/// <summary>
/// 轨迹拉取优先级配置详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<GetTrackPullPriorityDetailOutputVO> GetPriorityDetailAsync(int id);
Task<bool> InsertContentAsync(TrackPullContentConfigEntity insertObj);
Task<bool> InsertPriorityAsync(TrackPullPriorityEntity insertObj);
Task<bool> SoftDeleteContentAsync(Expression<Func<TrackPullContentConfigEntity, bool>> whereExpression);
Task<bool> SoftDeletePriorityAsync(Expression<Func<TrackPullPriorityEntity, bool>> whereExpression);
Task<TrackPullContentConfigEntity> GetContentByIdAsync(int id);
Task<TrackPullPriorityEntity> GetPriorityByIdAsync(int id);
Task<bool> UpdateContentAsync(TrackPullContentConfigEntity updateObj);
Task<bool> UpdatePriorityAsync(TrackPullPriorityEntity updateObj);
Task<bool> IsContentAnyAsync(Expression<Func<TrackPullContentConfigEntity, bool>> whereExpression);
Task<bool> IsPriorityAnyAsync(Expression<Func<TrackPullPriorityEntity, bool>> whereExpression);
Task<int> FindIdAsync(string appKey, string serviceProviderCode);
}

View File

@ -21,16 +21,10 @@ public class TrackPullConfigEntity : FullAuditedAggregateRoot<int, int>
public string AppKey { get; set; }
/// <summary>
/// 服务商id
/// 服务商代码
/// </summary>
[SugarColumn(ColumnName = "ServiceProviderId")]
public int ServiceProviderId { get; set; }
/// <summary>
/// 服务商拉取频率(分钟)
/// </summary>
[SugarColumn(ColumnName = "PullInterval")]
public int PullInterval { get; set; }
[SugarColumn(ColumnName = "ServiceProviderCode")]
public string? ServiceProviderCode { get; set; }
/// <summary>
/// 解析方式,1取接口通返参映射后的,2取服务商原返参
@ -97,4 +91,34 @@ public class TrackPullConfigEntity : FullAuditedAggregateRoot<int, int>
/// </summary>
[SugarColumn(ColumnName = "TrackTimeZoneName")]
public string? TrackTimeZoneName { get; set; }
/// <summary>
/// 订单类型
/// </summary>
[SugarColumn(ColumnName = "OrderType")]
public TrackOrderType OrderType { get; set; }
/// <summary>
/// 开始轨迹code
/// </summary>
[SugarColumn(ColumnName = "StartTrackCode")]
public string StartTrackCode { get; set; }
/// <summary>
/// 结束轨迹code
/// </summary>
[SugarColumn(ColumnName = "EndTrackCode")]
public string EndTrackCode { get; set; }
/// <summary>
/// 开始前的静默(小时)
/// </summary>
[SugarColumn(ColumnName = "SilenceBeforeStart")]
public int SilenceBeforeStart { get; set; }
/// <summary>
/// 结束后的静默(小时)
/// </summary>
[SugarColumn(ColumnName = "SilenceAfterEnd")]
public int SilenceAfterEnd { get; set; }
}

View File

@ -0,0 +1,40 @@
using Fake.Domain.Entities.Auditing;
namespace TrackCenter.Domain.Aggregates.TrackPullAggregate;
/// <summary>
/// 轨迹拉取优先级配置表
/// </summary>
[SugarTable("t_track_pull_priority_config")]
public class TrackPullPriorityEntity: FullAuditedEntity<int, int>
{
/// <summary>
/// 轨迹拉取配置id
/// </summary>
[SugarColumn(ColumnName = "TrackPullConfigId")]
public int TrackPullConfigId { get; set; }
/// <summary>
/// 客户
/// </summary>
[SugarColumn(ColumnName = "Customer")]
public string Customer { get; set; }
/// <summary>
/// 订单类型
/// </summary>
[SugarColumn(ColumnName = "OrderType")]
public TrackOrderType OrderType { get; set; }
/// <summary>
/// 优先级
/// </summary>
[SugarColumn(ColumnName = "优先级")]
public string Priority { get; set; }
/// <summary>
/// 服务商拉取频率(分钟)
/// </summary>
[SugarColumn(ColumnName = "PullInterval")]
public int PullInterval { get; set; }
}

View File

@ -1,3 +1,5 @@
using TrackCenter.Domain.Aggregates.OrderAggregate;
namespace TrackCenter.Domain.Dtos.TrackPull;
public class GetTrackPullConfigDetailOutputVO
@ -14,11 +16,6 @@ public class GetTrackPullConfigDetailOutputVO
/// </summary>
public int ParseMethod { get; set; }
/// <summary>
/// 定时任务(分钟)
/// </summary>
public int PullInterval { get; set; }
/// <summary>
/// 服务商id
/// </summary>
@ -83,4 +80,29 @@ public class GetTrackPullConfigDetailOutputVO
/// 轨迹明细路径
/// </summary>
public string TrackDetailsPath { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public TrackOrderType OrderType { get; set; }
/// <summary>
/// 开始轨迹code
/// </summary>
public string StartTrackCode { get; set; }
/// <summary>
/// 结束轨迹code
/// </summary>
public string EndTrackCode { get; set; }
/// <summary>
/// 开始前的静默(小时)
/// </summary>
public int SilenceBeforeStart { get; set; }
/// <summary>
/// 结束后的静默(小时)
/// </summary>
public int SilenceAfterEnd { get; set; }
}

View File

@ -0,0 +1,33 @@
using TrackCenter.Domain.Aggregates.TrackPullAggregate;
namespace TrackCenter.Domain.Dtos.TrackPull;
public class GetTrackPullPriorityDetailOutputVO
{
public int Id { get; set; }
/// <summary>
/// 轨迹拉取配置id
/// </summary>
public int TrackPullConfigId { get; set; }
/// <summary>
/// 客户
/// </summary>
public string Customer { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public TrackOrderType OrderType { get; set; }
/// <summary>
/// 优先级
/// </summary>
public string Priority { get; set; }
/// <summary>
/// 服务商拉取频率(分钟)
/// </summary>
public int PullInterval { get; set; }
}

View File

@ -0,0 +1,11 @@
using TrackCenter.Domain.Aggregates.TrackPullAggregate;
namespace TrackCenter.Domain.Dtos.TrackPull;
public class GetTrackPullPriorityPageInputVO : PageInfoInput
{
/// <summary>
/// 轨迹拉取配置id
/// </summary>
public int TrackPullConfigId { get; set; }
}

View File

@ -0,0 +1,36 @@
using TrackCenter.Domain.Aggregates.TrackPullAggregate;
namespace TrackCenter.Domain.Dtos.TrackPull;
public class GetTrackPullPriorityPageOutputVO
{
public int Id { get; set; }
/// <summary>
/// 客户
/// </summary>
public string Customer { get; set; }
/// <summary>
/// 订单类型
/// </summary>
public TrackOrderType OrderType { get; set; }
/// <summary>
/// 优先级
/// </summary>
public string Priority { get; set; }
/// <summary>
/// 服务商拉取频率(分钟)
/// </summary>
public int PullInterval { get; set; }
public DateTime CreateTime { get; set; }
public string? CreateUser { get; set; }
public string? UpdateUser { get; set; }
public DateTime? UpdateTime { get; set; }
}

View File

@ -7,11 +7,6 @@ public class TrackPullConfigVo
/// </summary>
public int PullInterval { get; set; }
/// <summary>
/// 服务商id
/// </summary>
public int ServiceProviderId { get; set; }
/// <summary>
/// 服务商code
/// </summary>

View File

@ -4,5 +4,7 @@ public enum TrackOrderType
{
小包 = 1,
大包 = 2,
主单 = 4,
}

View File

@ -16,12 +16,6 @@ public interface IBasicRepository<T> : IRepository<T> where T : class, IAggregat
Task<TResult?> GetFirstAsync<TResult>(Expression<Func<T, bool>> whereExpression,Expression<Func<T, TResult>> resultExpression);
/// <summary>
/// get list
/// </summary>
/// <param name="whereExpression"></param>
/// <returns></returns>
Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression);
Task<List<TResult>> GetListAsync<TResult>(Expression<Func<T, bool>> whereExpression,Expression<Func<T, TResult>> resultExpression);

View File

@ -31,11 +31,6 @@ public class BasicRepository<T> : SqlSugarRepository<TrackCenterDbContext, T>, I
return await Context.Queryable<T>().Where(whereExpression).Select(resultExpression).FirstAsync();
}
public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression)
{
return await AsQueryable().Where(whereExpression).ToListAsync();
}
public async Task<List<TResult>> GetListAsync<TResult>(Expression<Func<T, bool>> whereExpression,
Expression<Func<T, TResult>> resultExpression)
{

View File

@ -239,10 +239,10 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
await UpdateAsync(order, x => new
{
x.Customer,
x.AppKey
x.AppKey,
});
// 更新订单模板
// 更新订单拉取状态
await Context.Deleteable<OrderPullStatusEntity>().Where(x => x.OrderId == order.Id).ExecuteCommandAsync();
order.OrderPullStatus.ForEach(x => x.OrderId = order.Id);
await Context.Insertable(order.OrderPullStatus).ExecuteCommandAsync();

View File

@ -16,7 +16,7 @@ public class TrackPullConfigRepository : BasicRepository<TrackPullConfigEntity>,
{
return await Context.Queryable<TrackPullConfigEntity>()
.LeftJoin<VAppEntity>((trackPull, system) => trackPull.AppKey == system.AppKey)
.LeftJoin<VServiceProviderEntity>((trackPull, system, service) => trackPull.ServiceProviderId == service.Id)
.LeftJoin<VServiceProviderEntity>((trackPull, system, service) => trackPull.ServiceProviderCode == service.Code)
.WhereIF(!input.AppKey.IsNullOrWhiteSpace(), trackPull => trackPull.AppKey == input.AppKey)
.WhereIF(!input.Keywords.IsNullOrWhiteSpace(),
(trackPull, system, service) => service.Name.Contains(input.Keywords!))
@ -81,7 +81,7 @@ public class TrackPullConfigRepository : BasicRepository<TrackPullConfigEntity>,
{
return await AsQueryable()
.LeftJoin<VAppEntity>((trackPull, system) => trackPull.AppKey == system.AppKey)
.LeftJoin<VServiceProviderEntity>((trackPull, system, service) => trackPull.ServiceProviderId == service.Id)
.LeftJoin<VServiceProviderEntity>((trackPull, system, service) => trackPull.ServiceProviderCode == service.Code)
.Where(trackPull => trackPull.Id == id)
.Select(
(trackPull, system, service) => new GetTrackPullConfigDetailOutputVO
@ -91,6 +91,22 @@ public class TrackPullConfigRepository : BasicRepository<TrackPullConfigEntity>,
AppKey = system.AppKey,
ServiceProviderId = service.Id,
ServiceProviderCode = service.Code,
OrderNoName = trackPull.OrderNoName,
ParseMethod = (int)trackPull.ParseMethod,
TrackIsoTimeName = trackPull.TrackIsoTimeName,
TrackTimeName = trackPull.TrackTimeName,
TrackTimeZoneName = trackPull.TrackTimeZoneName,
TrackContentCodeName = trackPull.TrackContentCodeName,
TrackContentName = trackPull.TrackContentName,
TrackPlaceName = trackPull.TrackPlaceName,
TrackStatusName = trackPull.TrackStatusName,
OrderPath = trackPull.OrderPath,
TrackDetailsPath = trackPull.TrackDetailsPath,
OrderType = trackPull.OrderType,
StartTrackCode = trackPull.StartTrackCode,
EndTrackCode = trackPull.EndTrackCode,
SilenceBeforeStart = trackPull.SilenceBeforeStart,
SilenceAfterEnd = trackPull.SilenceAfterEnd
}, true)
.FirstAsync();
}
@ -122,12 +138,54 @@ public class TrackPullConfigRepository : BasicRepository<TrackPullConfigEntity>,
.SingleAsync();
}
public async Task<PagedResult<GetTrackPullPriorityPageOutputVO>> GetPriorityPageAsync(GetTrackPullPriorityPageInputVO input)
{
return await Context.Queryable<TrackPullPriorityEntity>()
.LeftJoin<VUserEntity>((x, creator) => x.CreateUserId == creator.UserId)
.LeftJoin<VUserEntity>((x, creator, modifier) => x.UpdateUserId == modifier.UserId)
.Where(x => x.TrackPullConfigId == input.TrackPullConfigId)
.OrderByDescending(x => x.Priority)
.Select((x, creator, modifier) => new GetTrackPullPriorityPageOutputVO
{
Id = x.Id,
Customer = x.Customer,
OrderType = x.OrderType,
Priority = x.Priority,
PullInterval = x.PullInterval,
CreateTime = x.CreateTime,
CreateUser = creator.Name,
UpdateUser = modifier.Name,
UpdateTime = x.UpdateTime
})
.ToPagedListAsync(input.PageIndex, input.PageSize);
}
public async Task<GetTrackPullPriorityDetailOutputVO> GetPriorityDetailAsync(int id)
{
return await Context.Queryable<TrackPullPriorityEntity>()
.Where(x => x.Id == id)
.Select(x => new GetTrackPullPriorityDetailOutputVO
{
Id = x.Id,
TrackPullConfigId = x.TrackPullConfigId,
Customer = x.Customer,
OrderType = x.OrderType,
Priority = x.Priority,
PullInterval = x.PullInterval
})
.SingleAsync();
}
public async Task<bool> InsertContentAsync(TrackPullContentConfigEntity insertObj)
{
return await Context.Insertable(insertObj).ExecuteCommandAsync() > 0;
}
public async Task<bool> InsertPriorityAsync(TrackPullPriorityEntity insertObj)
{
return await Context.Insertable(insertObj).ExecuteCommandAsync() > 0;
}
public async Task<bool> SoftDeleteContentAsync(Expression<Func<TrackPullContentConfigEntity, bool>> whereExpression)
{
return await Context.Updateable<TrackPullContentConfigEntity>()
@ -136,27 +194,49 @@ public class TrackPullConfigRepository : BasicRepository<TrackPullConfigEntity>,
.ExecuteCommandHasChangeAsync();
}
public async Task<bool> SoftDeletePriorityAsync(Expression<Func<TrackPullPriorityEntity, bool>> whereExpression)
{
return await Context.Updateable<TrackPullPriorityEntity>()
.Where(whereExpression)
.SetColumns(nameof(ISoftDelete.IsDeleted), true)
.ExecuteCommandHasChangeAsync();
}
public async Task<TrackPullContentConfigEntity> GetContentByIdAsync(int id)
{
return await Context.Queryable<TrackPullContentConfigEntity>().InSingleAsync(id);
}
public async Task<TrackPullPriorityEntity> GetPriorityByIdAsync(int id)
{
return await Context.Queryable<TrackPullPriorityEntity>().InSingleAsync(id);
}
public async Task<bool> UpdateContentAsync(TrackPullContentConfigEntity updateObj)
{
return await Context.Updateable(updateObj).ExecuteCommandHasChangeAsync();
}
public async Task<bool> UpdatePriorityAsync(TrackPullPriorityEntity updateObj)
{
return await Context.Updateable(updateObj).ExecuteCommandHasChangeAsync();
}
public async Task<bool> IsContentAnyAsync(Expression<Func<TrackPullContentConfigEntity, bool>> whereExpression)
{
return await Context.Queryable<TrackPullContentConfigEntity>().Where(whereExpression).AnyAsync();
}
public async Task<bool> IsPriorityAnyAsync(Expression<Func<TrackPullPriorityEntity, bool>> whereExpression)
{
return await Context.Queryable<TrackPullPriorityEntity>().Where(whereExpression).AnyAsync();
}
public async Task<int> FindIdAsync(string appKey, string serviceProviderCode)
{
return await AsQueryable()
.LeftJoin<VServiceProviderEntity>((trackPull, service) => trackPull.ServiceProviderId == service.Id)
.Where((trackPull, service) => trackPull.AppKey == appKey && service.Code == serviceProviderCode)
.Where(trackPull => trackPull.AppKey == appKey
&& trackPull.ServiceProviderCode == serviceProviderCode)
.Select(trackPull => trackPull.Id)
.FirstAsync();
}