Merge remote-tracking branch 'origin/S03-轨迹中台' into test

This commit is contained in:
dingenwen 2024-04-08 09:05:09 +08:00
commit fd258a406c
12 changed files with 153 additions and 113 deletions

View File

@ -5,17 +5,18 @@ public class GetTrackOutput
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; }
public string OrderNo { get; set; } = null!;
public List<TrackDetail> TrackDetails { get; set; }
public List<TrackDetail> TrackDetails { get; set; } = new();
}
public class TrackDetail
{
public string Code { get; set; }
public string Status { get; set; }
public string Content { get; set; }
public string Location { get; set; }
public string Code { get; set; } = null!;
public string Status { get; set; } = null!;
public string? Content { get; set; }
public string? OriginContent { get; set; }
public string Location { get; set; } = null!;
public DateTime Time { get; set; }
public float TimeZone { get; set; }
}

View File

@ -22,6 +22,16 @@ public class TrackUpsertEvent
/// </summary>
public string? ServiceProviderName { get; set; }
/// <summary>
/// 原轨迹内容
/// </summary>
public string? OriginTrackContent { get; set; }
/// <summary>
/// 原轨迹报文
/// </summary>
public string? OriginTrackData { get; set; }
/// <summary>
/// 表示订单是否完成(只由轨迹刷新配置决定)
/// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新

View File

@ -12,6 +12,14 @@ public interface ITrackPushCacheService
/// <returns></returns>
Task<List<TrackPushContentConfigDto>?> GetPushContentConfigsAsync(int subSystemId, int customId);
/// <summary>
/// 设置服务商拉取配置缓存
/// </summary>
/// <param name="subSystemId"></param>
/// <param name="customId"></param>
/// <returns></returns>
Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int subSystemId, int customId);
/// <summary>
/// 获取服务商拉取配置
/// </summary>
@ -33,14 +41,4 @@ public interface ITrackPushCacheService
Task<TrackPushContentConfigDto?> IsValidPushAsync(int subSystemId, int customId,
string? latestPushTrackCode,
string? trackCode);
/// <summary>
/// 设置推送配置缓存
/// </summary>
/// <param name="id"></param>
/// <param name="subSystemId">子系统id</param>
/// <param name="customId">客户id</param>
/// <returns></returns>
Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int? id = null, int? subSystemId = null,
int? customId = null);
}

View File

@ -218,6 +218,7 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe
OrderType = context.OrderType,
OrderNo = context.OrderNo,
ServiceProviderName = context.ServiceProviderName,
OriginTrackData = JsonConvert.SerializeObject(trackToken),
IsCompleted = matchedContentConfig.IsCompleted,
SubSystemId = context.SubSystemId,
TrackCode = matchedContentConfig.TrackContentCode,
@ -225,6 +226,11 @@ public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe
TrackTime = trackTime ?? DateTime.Now,
TrackTimeZone = trackTimeZone ?? matchedContentConfig.TrackTimeZoneValue ?? 8
};
if (paramConfig.TrackContentName != null)
{
trackUpsertEvent.OriginTrackContent = trackToken[paramConfig.TrackContentName]?.Value<string>();
}
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, trackUpsertEvent);
}
}

View File

@ -131,6 +131,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackTime = @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone,
ServiceProviderName = @event.ServiceProviderName,
OriginTrackContent = @event.OriginTrackContent,
OriginTrackData = @event.OriginTrackData,
IsCanDelete = false,
CreateUser = @event.OperationMan ?? GlobalConst.SystemUser,
CreateTime = DateTime.Now

View File

@ -39,6 +39,7 @@ public partial class TrackService
Code = x.TrackCode,
Status = x.TrackStatus,
Content = x.TrackContent,
OriginContent = x.OriginTrackContent,
Location = x.TrackPlace,
Time = x.TrackTime.AddHours(input.TimeZone ?? 8 - x.TrackTimeZone),
TimeZone = input.TimeZone ?? 8
@ -54,6 +55,29 @@ public partial class TrackService
private async Task TrackDetailSort(List<GetTrackOutput> list, GetTrackInput input)
{
var orderTemplates = await _provideQueries
.GetOrderTemplateLinksAsync(input.OrderType, input.OrderNos);
var distinctTemplateIds = orderTemplates.Select(x => x.TemplateId).Distinct().ToList();
var templateContent = await _provideQueries.GetOrderedTrackCodesAsync(distinctTemplateIds);
list.ForEach(item =>
{
var codes = new List<string>();
// 多模板拼接显示
foreach (var orderTemplate in orderTemplates.Where(x => x.OrderNo == item.OrderNo))
{
codes.AddRange(templateContent
.Where(t => t.TemplateId == orderTemplate.TemplateId) // 按模板
.Where(t => t.IsExternal) // 过滤不对外的
.Select(t => t.Code));
}
item.TrackDetails = item.TrackDetails
.Where(x => codes.Contains(x.Code)) // 剔除不在模板内容中的元素
.OrderBy(x => codes.IndexOf(x.Code)) // 按照在模板内容的位置排序
.ToList();
});
switch (input.SortMethod)
{
case SortMethod.ByTrackTime:
@ -64,30 +88,21 @@ public partial class TrackService
list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time)));
break;
case SortMethod.ByTemplate:
var orderTemplates = await _provideQueries
.GetOrderTemplateLinksAsync(input.OrderType, input.OrderNos);
var distinctTemplateIds = orderTemplates.Select(x => x.TemplateId).Distinct().ToList();
var templateContent = await _provideQueries.GetOrderedTrackCodesAsync(distinctTemplateIds);
list.ForEach(item =>
{
var codes = new List<string>();
// 多模板拼接显示
foreach (var orderTemplate in orderTemplates.Where(x => x.OrderNo == item.OrderNo))
{
codes.AddRange(templateContent
.Where(t => t.TemplateId == orderTemplate.TemplateId) // 按模板
.Where(t => t.IsExternal) // 过滤不对外的
.Select(t => t.Code));
}
item.TrackDetails = item.TrackDetails
.Where(x => codes.Contains(x.Code)) // 剔除不在模板内容中的元素
.OrderBy(x => codes.IndexOf(x.Code)) // 按照在模板内容的位置排序
.ToList();
});
break;
default:
throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式");
}
// 显示原轨迹
list.ForEach(item =>
{
item.TrackDetails.ForEach(track =>
{
if (templateContent.First(x => x.Code == track.Code).ShowOrigin)
{
track.Content = track.OriginContent;
}
});
});
}
}

View File

@ -1,5 +1,4 @@
using System.Linq.Expressions;
using SJZY.Expand.ABP.Core;
using SJZY.Expand.ABP.Core;
using SJZY.Track.Application.Contract.Dtos.TrackPush;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
@ -22,11 +21,23 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
public async Task<List<TrackPushContentConfigDto>?> GetPushContentConfigsAsync(int subSystemId, int customId)
{
var data = await RedisHelper.Client.GetAsync<List<TrackPushContentConfigDto>>(
TrackPushContentKey(subSystemId, customId));
var exists = await RedisHelper.Client.ExistsAsync(TrackPushContentKey(subSystemId, customId));
if (exists)
{
return await RedisHelper.Client.GetAsync<List<TrackPushContentConfigDto>>(
TrackPushContentKey(subSystemId, customId));
}
data ??= await SetPushContentConfigsAsync(subSystemId: subSystemId, customId: customId);
return await SetPushContentConfigsAsync(subSystemId, customId);
}
public async Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int subSystemId, int customId)
{
// maybe is null
var data = await DoGetPushContentConfigsAsync(subSystemId, customId);
// ttl 3days
await RedisHelper.Client.SetAsync(TrackPushContentKey(subSystemId, customId),
data, 3 * 24 * 60 * 60);
return data;
}
@ -58,23 +69,23 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
return matched != null && matched.TrackCode == trackCode && matched.IsAutoPush ? matched : default;
}
public async Task<List<TrackPushContentConfigDto>?> SetPushContentConfigsAsync(int? id = null,
int? subSystemId = null,
int? customId = null)
private async Task<List<TrackPushContentConfigDto>?> DoGetPushContentConfigsAsync(int subSystemId, int customId)
{
Expression<Func<TrackPushConfigEntity, bool>> exp = x => true;
if (id.HasValue) exp = x => x.Id == id;
else if (subSystemId.HasValue && customId.HasValue)
exp = x => x.SubSystemId == subSystemId && x.CustomId == customId;
var trackPushConfig = await _trackPushConfigRepository.GetFirstAsync(exp, x => new
var trackPushConfig = await _trackPushConfigRepository.GetFirstAsync(
x => x.SubSystemId == subSystemId && x.CustomId == customId, x => new
{
x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId
});
if (trackPushConfig == null)
{
x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId
});
if (trackPushConfig == null) return null;
return null;
}
var trackPushContentList = await _trackPushConfigRepository.GetContentListAsync(trackPushConfig.Id);
if (trackPushContentList.Count == 0) return null;
if (trackPushContentList.Count == 0)
{
return null;
}
// tips:hot path,auto mapper性能不如原生
var res = trackPushContentList.Select(item => new TrackPushContentConfigDto
@ -95,9 +106,6 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc
ExpandFieldsValue = item.ExpandFieldsValue,
}).ToList();
await RedisHelper.Client.SetAsync(TrackPushContentKey(trackPushConfig.SubSystemId, trackPushConfig.CustomId),
res);
return res;
}
}

View File

@ -95,12 +95,17 @@ public class TrackPushService : ApplicationService
throw new BusinessException(message: _stringLocalizer["IsTrackPushConfigAny"]);
}
using var ts = TransactionScopeHelper.Create();
switch (input.Options)
{
case OptionTypeNoNull.新增:
{
var trackPushEntity = ObjectMapper.Map<EditTrackPushConfigInput, TrackPushConfigEntity>(input);
await _trackPushConfigRepository.InsertReturnIdentityAsync(trackPushEntity);
await _trackPushCacheService.SetPushContentConfigsAsync(trackPushEntity.SubSystemId,
trackPushEntity.CustomId);
}
break;
@ -111,21 +116,19 @@ public class TrackPushService : ApplicationService
ObjectMapper.Map(input, oldTrackPushEntity);
await _trackPushConfigRepository.UpdateAsync(oldTrackPushEntity);
if (input.IsAutoPush!.Value) await _trackPushCacheService.SetPushContentConfigsAsync(input.Id);
await _trackPushCacheService.SetPushContentConfigsAsync(oldTrackPushEntity.SubSystemId,
oldTrackPushEntity.CustomId);
}
break;
case OptionTypeNoNull.删除:
{
_ = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
throw new BusinessException(message: _stringLocalizer["NotFindData"]);
var entity = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
throw new BusinessException(message: _stringLocalizer["NotFindData"]);
using var ts = TransactionScopeHelper.Create();
await _trackPushConfigRepository.SoftDeleteAsync(x => x.Id == input.Id);
await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.TrackPushConfigId == input.Id);
ts.Complete();
await _trackPushCacheService.SetPushContentConfigsAsync(entity.SubSystemId, entity.CustomId);
}
break;
@ -134,6 +137,7 @@ public class TrackPushService : ApplicationService
nameof(EditTrackPushConfigInput.Options)]);
}
ts.Complete();
return true;
}
@ -172,6 +176,10 @@ public class TrackPushService : ApplicationService
throw new BusinessException(message: _stringLocalizer["IsTrackPushEnContentValueAny"]);
}
var trackPushConfigId = input.TrackPushConfigId;
using var ts = TransactionScopeHelper.Create();
switch (input.Options)
{
case OptionTypeNoNull.新增:
@ -181,10 +189,7 @@ public class TrackPushService : ApplicationService
var entity = ObjectMapper.Map<EditTrackPushContentInput, TrackPushContentConfigEntity>(input);
entity.Sort = maxSort + 1;
await _trackPushConfigRepository.InsertContentAsync(entity);
await _trackPushCacheService.SetPushContentConfigsAsync(input.TrackPushConfigId);
break;
}
@ -194,10 +199,7 @@ public class TrackPushService : ApplicationService
throw new BusinessException(message: _stringLocalizer["NotFindData"]);
ObjectMapper.Map(input, entity);
await _trackPushConfigRepository.UpdateContentAsync(entity);
await _trackPushCacheService.SetPushContentConfigsAsync(entity.TrackPushConfigId);
break;
}
@ -205,18 +207,10 @@ public class TrackPushService : ApplicationService
{
var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: _stringLocalizer["NotFindData"]);
using (var ts = TransactionScopeHelper.Create())
{
await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id);
await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1,
x => x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort);
ts.Complete();
}
await _trackPushCacheService.SetPushContentConfigsAsync(entity.TrackPushConfigId);
trackPushConfigId = entity.TrackPushConfigId;
await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id);
await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1,
x => x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort);
break;
}
@ -225,6 +219,14 @@ public class TrackPushService : ApplicationService
nameof(EditTrackPushContentInput.Options)]);
}
var pushConfig = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == trackPushConfigId);
if (pushConfig != null)
{
await _trackPushCacheService.SetPushContentConfigsAsync(pushConfig.SubSystemId, pushConfig.CustomId);
}
ts.Complete();
return true;
}
@ -247,8 +249,19 @@ public class TrackPushService : ApplicationService
if (trackPushContentEntities.Count > 0)
{
using var ts = TransactionScopeHelper.Create();
await _trackPushConfigRepository.UpdateContentRangeAsync(trackPushContentEntities);
await _trackPushCacheService.SetPushContentConfigsAsync(trackPushContentEntities[0].TrackPushConfigId);
var pushConfig =
await _trackPushConfigRepository.GetFirstAsync(x =>
x.Id == trackPushContentEntities[0].TrackPushConfigId);
if (pushConfig != null)
{
await _trackPushCacheService.SetPushContentConfigsAsync(pushConfig.SubSystemId, pushConfig.CustomId);
}
ts.Complete();
}
return true;

View File

@ -1,7 +0,0 @@
namespace SJZY.Track.Application.Services.TrackTemplates
{
public interface ITrackTemplateService
{
}
}

View File

@ -16,4 +16,9 @@ public class OrderedTrackCodeDto
/// 是否对外
/// </summary>
public bool IsExternal { get; set; }
/// <summary>
/// 显示原轨迹
/// </summary>
public bool ShowOrigin { get; set; }
}

View File

@ -20,20 +20,6 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
Context = SqlsugarScopeBasic.GetContextSafely("default");
}
public async Task<List<OrderTemplateLinkDto>> GetOrderTemplateLinksAsync(int orderType,
params string[] orderNumbers)
{
return await Context.Queryable<OrderEntity>()
.LeftJoin<OrderTemplateEntity>((a, b) => a.Id == b.OrderId)
.Where(a => a.OrderType == orderType && orderNumbers.Contains(a.OrderNo))
.Select((a, b) => new OrderTemplateLinkDto
{
OrderNo = a.OrderNo,
TemplateId = b.TrackTemplateId
})
.ToListAsync();
}
public async Task<List<OrderTemplateLinkDto>> GetOrderTemplateLinksAsync(int orderType, List<string> orderNumbers)
{
return await Context.Queryable<OrderEntity>()
@ -49,15 +35,17 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
public async Task<List<OrderedTrackCodeDto>> GetOrderedTrackCodesAsync(List<int> templateIds)
{
return await Context.Queryable<TrackTemplateContentEntity>()
.LeftJoin<TrackContentEntity>((a, b) => a.TrackContentId == b.Id)
.Where(a => templateIds.Contains(a.TrackTemplateId))
.OrderBy(a => a.Sort)
.Select((a, b) => new OrderedTrackCodeDto
return await Context.Queryable<TrackTemplateEntity>()
.LeftJoin<TrackTemplateContentEntity>((a, b) => a.Id == b.TrackTemplateId)
.LeftJoin<TrackContentEntity>((a, b, c) => b.TrackContentId == c.Id)
.Where(a => templateIds.Contains(a.Id))
.OrderBy((a, b) => b.Sort)
.Select((a, b, c) => new OrderedTrackCodeDto
{
TemplateId = a.TrackTemplateId,
Code = b.Code,
IsExternal = a.IsExternal
TemplateId = a.Id,
ShowOrigin = a.ShowOrigin,
Code = c.Code,
IsExternal = b.IsExternal
})
.ToListAsync();
}

View File

@ -85,6 +85,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
.Field(f => f.TrackStatus)
.Field(f => f.TrackCode)
.Field(f => f.TrackContent)
.Field(f => f.OriginTrackContent)
.Field(f => f.TrackPlace)
.Field(f => f.TrackTime)
.Field(f => f.TrackTimeZone)