Merge branch 'S06' into test

This commit is contained in:
hardstylewyl 2025-01-14 10:52:10 +08:00
commit 6afc29945b
7 changed files with 351 additions and 74 deletions

View File

@ -22,6 +22,14 @@ public interface IBroadcastingService : ITransientDependency
/// <param name="trackStatusCode"></param>
void TrackChangePublicTopicAsync(TrackDeleteEvent eto, OrderIdentifier[] orderIdentifiers, string trackCode, string trackStatusCode, string subSystemCode);
/// <summary>
/// 轨迹变更广播(删除)
/// </summary>
/// <param name="eto"></param>
/// <param name="subSystemCode"></param>
/// <param name="trackStatusCode"></param>
void TrackChangePublicTopicAsync(TrackChangeEto eto, string subSystemCode);
/// <summary>
/// 轨迹推送完成广播(推送完成回调)
/// </summary>

View File

@ -1,9 +1,12 @@
using System.Collections.Immutable;
using System.Text.Json;
using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Helpers;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Enums;
@ -118,7 +121,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
return true;
}
private async Task PublicTrackTopicAsync(TrackDeleteEvent eto, List<TrackDetailsIndex> trackList)
private async Task PublicTrackTopicAsync(TrackDeleteEvent @event, List<TrackDetailsIndex> trackList)
{
var systemIds = trackList.Select(x => x.SubSystemId).Distinct().ToArray();
var trackCodes = trackList.Select(x => x.TrackCode).Distinct().ToArray();
@ -144,21 +147,63 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
var item = dataItem.First();
var content = contentList.First(m => m.TrackContentCode == item.TrackCode);
_broadcastingService.TrackChangePublicTopicAsync(eto,
dataItem.Select(m => new OrderIdentifier
// _broadcastingService.TrackChangePublicTopicAsync(track,
// dataItem.Select(m => new OrderIdentifier
// {
// OrderId = m.OrderId,
// OrderNo = m.OrderNo,
// OrderType = m.OrderType
// }).ToArray(),
// item.TrackCode,
// item.TrackStatusCode,
// content.SubSystemCode
// );
//将每个订单的每个轨迹的删除变更发布
foreach (var track in dataItem)
{
_broadcastingService.TrackChangePublicTopicAsync(new TrackChangeEto
{
OrderId = m.OrderId,
OrderNo = m.OrderNo,
OrderType = m.OrderType
}).ToArray(),
item.TrackCode,
item.TrackStatusCode,
content.SubSystemCode
);
EstimatedDeliveryDate = track.EstimatedDeliveryDate,
TrackPlacePostcode = track.TrackPlacePostcode,
TrackPlaceNation = track.TrackPlaceNation,
TrackPlaceNationId = track.TrackPlaceNationId,
TrackPlaceProvince = track.TrackPlaceProvince,
TrackPlaceProvinceId = track.TrackPlaceProvinceId,
TrackPlaceCity = track.TrackPlaceCity,
TrackPlaceCityId = track.TrackPlaceCityId,
Files = track.Files?.Select(x => new FileItemDto()
{
FileName = x.FileName,
OssKey = x.OssKey
}).ToList(),
Remarks = track.Remarks,
Source = track.Source,
IsVisibility = track.IsVisibility,
TrackTimeZone = track.TrackTimeZone,
TrackTime = track.TrackTime,
TrackPlace = track.TrackPlace,
TrackStatusCode = track.TrackStatusCode,
EnStatus = track.TrackEnContent,
Content = track.TrackContent,
TrackCode = track.TrackCode,
OperationMan = @event.OperationMan,
OrderIdentifiers = new[]
{
new OrderIdentifier()
{
OrderId = track.OrderId,
OrderNo = track.OrderNo,
OrderType = track.OrderType
}
},
SubSystemId = @event.SubSystemId,
Extra = track.Extra
}, content.SubSystemCode);
}
}
}
// todo:多个相同code的轨迹删除,也需要考虑??
private async Task<List<TrackDetailsIndex>> DeleteTrackAsync(TrackDeleteEvent @event)
{
List<int> orderIds;
@ -196,10 +241,40 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
//根据订单查询出所有的轨迹,查所有是因为主单上需要进行回退更新
tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds);
//构建标识符集合
var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToList();
//根据标识符选出要删除的轨迹明细
deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList();
//比较字段为空则使用时间来作为额外的标识key
if (string.IsNullOrWhiteSpace(@event.CompareFields))
{
//构建标识符集合
var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToHashSet();
//根据标识符选出要删除的轨迹明细
deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList();
}
//否则则使用比较字段,使用扩展字段中的内容进行比较
else
{
var codes = @event.TrackIdentifiers.Select(x => x.TrackCode).ToImmutableHashSet();
deleteTracks = tracks
.Where(x =>
{
if (!codes.Contains(x.TrackCode))
return false;
if (string.IsNullOrWhiteSpace(x.Extra))
{
throw new BusinessException(message: $"当前轨迹不存在扩展信息,无法利用扩展字段:{@event.CompareFields}");
}
var extraDict = GetExtraDictForTextJson(x.Extra);
if (extraDict == null || !extraDict.TryGetValue(@event.CompareFields, out var compareValue))
{
throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{@event.CompareFields}");
}
return TextJsonHelper.EqJsonElement(compareValue, @event.CompareValue);
})
.ToList();
}
if (deleteTracks.Count == 0) return deleteTracks;
@ -256,21 +331,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
order.EstimatedDeliveryDate = track.EstimatedDeliveryDate;
order.DestinationTimeZone = track.DestinationTimeZone;
}
// 写入操作日志
_ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex
{
OrderId = order.Id,
OrderNo = order.OrderNo,
OptionType = OrderOperationType.删除轨迹.ToString(),
Content = deleteTracks.Where(m => m.OrderId == order.Id).ToList().ToJson(),
CreateUserId = @event.OperationManId,
CreateUserName = @event.OperationMan ?? "",
CreateTime = DateTime.Now
});
}
//更新订单上冗余轨迹明细的字段
await _orderRepository.UpdateRangeAsync(orders,
x => new
{
@ -283,6 +346,83 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
x.DestinationTimeZone
});
//批量写入订单操作日志
_ = _orderOperationRecordEsRepository.AddManyAsync(orders.Select(order => new OrderOperationRecordIndex
{
OrderId = order.Id,
OrderNo = order.OrderNo,
OptionType = OrderOperationType.删除轨迹.ToString(),
Content = deleteTracks.Where(m => m.OrderId == order.Id).ToList().ToJson(),
CreateUserId = @event.OperationManId,
CreateUserName = @event.OperationMan ?? "",
CreateTime = DateTime.Now
}).ToList());
return deleteTracks;
}
private Dictionary<string, object?>? GetExtraDictForTextJson(string? extraStr)
{
return string.IsNullOrWhiteSpace(extraStr)
? null
: System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(extraStr);
}
//json Element和object的比较
private bool EqJsonElementObject2(object? a, object? b)
{
if (a == null && b == null)
{
return true;
}
if (a is JsonElement aJsonElement)
{
switch (aJsonElement.ValueKind)
{
case JsonValueKind.Undefined:
return false;
case JsonValueKind.Object:
return false;
case JsonValueKind.Array:
return false;
case JsonValueKind.String:
return string.Equals(aJsonElement.GetString(), b as string);
case JsonValueKind.Number:
{
if (b == null) return false;
if (b is int bInt)
{
var aInt = aJsonElement.GetInt32();
return aInt == bInt;
}
if (b is long bLong)
{
var aLong = aJsonElement.GetInt64();
return aLong == bLong;
}
return false;
}
case JsonValueKind.True:
case JsonValueKind.False:
{
if (b is bool bl)
{
return aJsonElement.GetBoolean() == bl;
}
return false;
}
case JsonValueKind.Null:
{
return false;
}
}
}
return false;
}
}

View File

@ -123,6 +123,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
TrackPushFailedPublicTopic($"推送顺序异常,下一个要推送的应为[{nextCode}]", @event, order);
continue;
}
config = resultConfig;
// 是否自动推送
@ -316,7 +317,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
{ "descriptionCn", config.TrackContentValue },
{ "code", config.TrackContentCodeValue },
{ "status", config.TrackStatusValue },
{ "extra", DeserializeForTextJson<object>(log.Extra) }
{ "extra", TextJsonHelper.Deserialize<object>(log.Extra) }
};
body.Data.Add(dict);
log.PushContent = body.ToJson();
@ -344,7 +345,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
{ "descriptionCn", config.TrackContentValue },
{ "code", config.TrackContentCodeValue },
{ "status", config.TrackStatusValue },
{ "extra", DeserializeForTextJson<object>(log.Extra) }
{ "extra", TextJsonHelper.Deserialize<object>(log.Extra) }
};
body.Data.Add(cur);
@ -353,7 +354,9 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId);
if (history != default)
{
body = DeserializeForTextJson<TrackPushInput>(history.PushContent);
body = TextJsonHelper.Deserialize<TrackPushInput>(history.PushContent);
//在历史选出推送成功的历史轨迹
if (config.IsAllPushWithLatest)
{
//同code同比较字段保证唯一
@ -367,22 +370,22 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
}).WhereIf(!compareFields.IsNullOrWhiteSpace(), x =>
{
if (x["extra"] == null || log.Extra == null) return false;
return EqExtraByFieldForTextJson(x["extra"]!, DeserializeForTextJson<JsonElement>(log.Extra), compareFields!);
return TextJsonHelper.EqByJsonElementField(x["extra"]!, TextJsonHelper.Deserialize<JsonElement>(log.Extra), compareFields!);
})
.FirstOrDefault();
if (old != null)
{
body.Data.Remove(old);
}
//根据code和比较字段值分组,在每组里选出一个创建时间最新的
}
body!.Data.Add(cur);
}
}
log.PushContent = SerializeForTextJson(body);
log.PushContent = TextJsonHelper.Serialize(body)!;
return body;
}
@ -431,31 +434,6 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
return dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK");
}
private static string SerializeForTextJson(object? obj)
{
return obj == null ? string.Empty : System.Text.Json.JsonSerializer.Serialize(obj);
}
private static T? DeserializeForTextJson<T>(string? json)
{
return string.IsNullOrWhiteSpace(json) ? default : System.Text.Json.JsonSerializer.Deserialize<T>(json);
}
//比较扩展中的某个字段的相等性
private bool EqExtraByFieldForTextJson(object a, object b, string fieldName)
{
if (a is not JsonElement aJsonElement || b is not JsonElement bJsonElement)
return false;
if (aJsonElement.TryGetProperty(fieldName, out var aValue)
&& bJsonElement.TryGetProperty(fieldName, out var bValue))
{
return aValue.ToString() == bValue.ToString();
}
return false;
}
//轨迹推送失败(被拦截)
private void TrackPushFailedPublicTopic(
string failedMessage,
@ -503,7 +481,7 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe
PushTime = DateTime.Now,
OptionType = @event.OptionType.ToString(),
IsManualPush = @event.OperationMan != null,
PushContent = SerializeForTextJson(pushInput),
PushContent = TextJsonHelper.Serialize(pushInput),
OrderNo = pushInput.OrderNo,
TrackStatus = @event.SystemPushInfo.TrackStatus,
TrackContent = @event.SystemPushInfo.TrackStatus,

View File

@ -1,11 +1,11 @@
using System.Diagnostics;
using System.Text.Json;
using DotNetCore.CAP;
using Microsoft.Extensions.Logging;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Helpers;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Dtos.TrackContents;
@ -290,7 +290,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
return false;
}
return EqJsonElementObject(oldValue, compareValue);
return TextJsonHelper.EqJsonElement(oldValue, compareValue);
}).ToList();
}
@ -437,16 +437,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
: System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(extraStr);
}
private bool EqJsonElementObject(object? a, object? b)
{
if (a is JsonElement aJsonElement && b is JsonElement bJsonElement)
{
return aJsonElement.ToString() == bJsonElement.ToString();
}
return false;
}
private OrderOperationRecordIndex BuildOrderOperationRecord(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order)
{
return new OrderOperationRecordIndex

View File

@ -0,0 +1,125 @@
using System.Text.Json;
namespace SJZY.Track.Application.Helpers;
/// <summary>
/// 针对 Text.Json 的一些辅助方法
/// </summary>
public static class TextJsonHelper
{
public static string? Serialize(object? obj)
{
return obj == null ? default : System.Text.Json.JsonSerializer.Serialize(obj);
}
public static T? Deserialize<T>(string? json)
{
return string.IsNullOrWhiteSpace(json) ? default : System.Text.Json.JsonSerializer.Deserialize<T>(json);
}
/// <summary>
/// 两个jsonElement进行比较
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static bool EqJsonElement(object? a, object? b)
{
if (a == null && b == null)
{
return true;
}
if (a is JsonElement aJsonElement && b is JsonElement bJsonElement)
{
return aJsonElement.ToString() == bJsonElement.ToString();
}
return false;
}
/// <summary>
/// jsonElement和object之间的比较
/// </summary>
/// <param name="jsonElement"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static bool EqJsonElementAndObject(object? jsonElement, object? obj)
{
if (jsonElement == null && obj == null)
{
return true;
}
if (jsonElement is JsonElement aJsonElement)
{
switch (aJsonElement.ValueKind)
{
case JsonValueKind.Undefined:
return false;
case JsonValueKind.Object:
return false;
case JsonValueKind.Array:
return false;
case JsonValueKind.String:
return string.Equals(aJsonElement.GetString(), obj as string);
case JsonValueKind.Number:
{
if (obj == null) return false;
if (obj is int bInt)
{
var aInt = aJsonElement.GetInt32();
return aInt == bInt;
}
if (obj is long bLong)
{
var aLong = aJsonElement.GetInt64();
return aLong == bLong;
}
return false;
}
case JsonValueKind.True:
case JsonValueKind.False:
{
if (obj is bool bl)
{
return aJsonElement.GetBoolean() == bl;
}
return false;
}
case JsonValueKind.Null:
{
return false;
}
}
}
return false;
}
/// <summary>
/// 比较两个jsonElement中的的fieldName字段的值
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="fieldName"></param>
/// <returns></returns>
public static bool EqByJsonElementField(object a, object b, string fieldName)
{
if (a is not JsonElement aJsonElement || b is not JsonElement bJsonElement)
return false;
if (aJsonElement.TryGetProperty(fieldName, out var aValue)
&& bJsonElement.TryGetProperty(fieldName, out var bValue))
{
return aValue.ToString() == bValue.ToString();
}
return false;
}
}

View File

@ -81,6 +81,12 @@ public class BroadcastingService : IBroadcastingService
Encoding.UTF8.GetBytes(data.ToJson()));
}
public void TrackChangePublicTopicAsync(TrackChangeEto eto, string subSystemCode)
{
_rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{subSystemCode}",
Encoding.UTF8.GetBytes(eto.ToJson()));
}
/// <summary>
/// 轨迹推送完成广播
/// </summary>

View File

@ -5,6 +5,7 @@ using SJZY.Track.Application.Contract.Dtos.TrackOrder;
using SJZY.Track.Application.Contract.Dtos.TrackPush;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services.ProvideServices;
using SJZY.Track.Application.Helpers;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
@ -92,6 +93,28 @@ public class TrackPushService : ApplicationService, ITrackPushService
throw new BusinessException(message: "没有需要推送的轨迹");
}
//存在比较字段,需要做过滤处理
if (!string.IsNullOrWhiteSpace(input.CompareFields))
{
//根据输入值来进行过滤,比如选取code1,批次1的轨迹,可能会有多条,下面使用创建时间最新的一条
tracks = tracks.Where(x =>
{
if (string.IsNullOrWhiteSpace(x.Extra))
{
throw new BusinessException(message: $"当前轨迹不存在扩展信息,无法利用扩展字段:{input.CompareFields}");
}
var extraDict = GetExtraDictForTextJson(x.Extra);
if (extraDict == null || !extraDict.TryGetValue(input.CompareFields, out var compareValue))
{
throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{input.CompareFields}");
}
//补充轨迹内容
return TextJsonHelper.EqJsonElementAndObject(compareValue, input.CompareValue);
}).ToList();
}
//不同单可能会有不同的轨迹内容,先推送只推送最新的一条
foreach (var order in orders)
{
@ -117,7 +140,7 @@ public class TrackPushService : ApplicationService, ITrackPushService
TrackPlace = track.TrackPlace,
TrackTime = track.TrackTime,
TrackTimeZone = track.TrackTimeZone,
// todo: 这里也要改,重复code问题,到底推哪个
CompareFields = input.CompareFields,
Extra = track.Extra
}
};
@ -186,4 +209,11 @@ public class TrackPushService : ApplicationService, ITrackPushService
var res = ObjectMapper.Map<List<TrackPushRecordIndex>, List<TrackPushRecordOutput>>(records);
return new UnifyResultDto<List<TrackPushRecordOutput>>(true, res, "操作成功");
}
private Dictionary<string, object?>? GetExtraDictForTextJson(string? extraStr)
{
return string.IsNullOrWhiteSpace(extraStr)
? null
: System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(extraStr);
}
}