diff --git a/src/SJZY.Track.Api/appsettings.json b/src/SJZY.Track.Api/appsettings.json index 41fc37c6..ac8a5882 100644 --- a/src/SJZY.Track.Api/appsettings.json +++ b/src/SJZY.Track.Api/appsettings.json @@ -7,7 +7,7 @@ "Apollo": { "AppId": "SJZY.Track.Configuration", "Env": "DEV", - "Namespace": "test", + "Namespace": "dev", "MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080", "ConfigServer": [ "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080" diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs index e69de29b..9294efc0 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class GetDetailTimelineInput +{ + /// + /// 订单编号 + /// + public string OrderNumber { get; set; } + + /// + /// 子系统id + /// + public int SystemId{ get; set; } + + /// + /// 是否客户端,false时展示所有轨迹,true时只展示对外的轨迹 + /// + public bool IsCustomeClient { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs index e69de29b..a621240b 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs @@ -0,0 +1,54 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class GetDetailTimelineOutput +{ + /// + /// 轨迹编码 + /// + public string TrackCode { get; set; } + + /// + /// 轨迹内容 + /// + public string Content { get; set; } + + /// + /// 轨迹英文内容 + /// + public string EnContent { get; set; } + + /// + /// 轨迹发生地 + /// + public string TrackPlace { get; set; } = null!; + + /// + /// 轨迹发生时间 + /// + public long TrackTime { get; set; } + + /// + /// 轨迹时间前缀 + /// + public string TrackTimePrefix { get; set; } + + /// + /// 轨迹发生时区 + /// + public string TrackTimeZone { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 文件 osskey 集合 + /// + public List Files { get; set; } + + /// + /// 是否高亮 + /// + public bool IsHighlight { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs index 6b7c663f..14b5461e 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs @@ -46,6 +46,26 @@ public class EditTrackContentInput /// 是否对外 /// public bool IsExternal { get; set; } + + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } + + /// + /// 是否同步轨迹订单上的预计到达时间 + /// + public bool IsChangeOrderEdd { get; set; } } public class GetTrackContentDetailDto diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs index e69de29b..fb6aa163 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs @@ -0,0 +1,25 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetAvailableContentInput +{ + /// + /// 子系统id + /// + public int SystemId { get; set; } + + /// + /// 订单号 + /// + public string? OrderNo { get; set; } + + /// + /// 操作类型 1=创建 2=修改 + /// + public TrackOptionType TrackOptionType { get; set; } +} + +public enum TrackOptionType +{ + 创建 = 1, + 修改 = 2 +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs index e69de29b..69e77773 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetAvailableContentOutput +{ + /// + /// Id + /// + public int Id { get; set; } + + /// + /// 轨迹内容代码 + /// + public string Code { get; set; } + + /// + /// 轨迹内容 + /// + public string Content { get; set; } + + /// + /// 轨迹内容英文 + /// + public string EnContent { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs index e69de29b..8f7b1c85 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetTrackContentByCodeInput +{ + /// + /// 子系统id + /// + public int SystemId { get; set; } + + /// + /// 轨迹内容code + /// + public string Code { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs index e69de29b..e584522d 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetTrackContentByCodeOutput +{ + /// + /// 中文内容 + /// + public string Content { get; set; } + + /// + /// 英文内容 + /// + public string EnContent { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } +} diff --git a/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs b/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs index faf3f428..b4bea62f 100644 --- a/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs +++ b/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs @@ -2,9 +2,12 @@ using System.Linq.Expressions; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackContents; using SJZY.Track.Application.Localization; +using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; +using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.TrackContents; @@ -23,17 +26,23 @@ public class TrackContentService : ApplicationService private readonly ITrackContentRepository _trackContentRepository; private readonly IBasicQuery _trackFlagBasicQuery; private readonly IBasicQuery _trackStatusBasicQuery; + private readonly IOrderRepository _orderRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; public TrackContentService( IStringLocalizer stringLocalizer, ITrackContentRepository trackContentRepository, IBasicQuery trackStatusBasicQuery, - IBasicQuery trackFlagBasicQuery) + IBasicQuery trackFlagBasicQuery, + IOrderRepository orderRepository, + ITrackDetailsEsRepository trackDetailsEsRepository) { _stringLocalizer = stringLocalizer; _trackContentRepository = trackContentRepository; _trackStatusBasicQuery = trackStatusBasicQuery; _trackFlagBasicQuery = trackFlagBasicQuery; + _orderRepository = orderRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; } /// @@ -96,8 +105,7 @@ public class TrackContentService : ApplicationService /// /// [HttpPost("GetList")] - public async Task> GetPageTrackContent( - GetPageTrackContentInput input) + public async Task> GetPageTrackContent(GetPageTrackContentInput input) { var vo = ObjectMapper.Map(input); var resultDto = await _trackContentRepository.GetPageTrackContent(vo); @@ -181,6 +189,95 @@ public class TrackContentService : ApplicationService return true; } + /// + /// 根据轨迹内容code获取轨迹内容 + /// + /// + /// + [HttpPost("GetTrackContentByCode")] + public async Task> GetTrackContentByCodeAsync([FromBody] GetTrackContentByCodeInput input) + { + if (input.SystemId <= 0) + return new UnifyResultDto(false, "子系统Id必须大于等于0"); + + if (string.IsNullOrEmpty(input.Code)) + return new UnifyResultDto(false, "轨迹内容code不能为空"); + + var content = await _trackContentRepository.GetByCodeAsync(input.SystemId, input.Code); + if (content == null) + return new UnifyResultDto(false, "在当前子系统中未找到指定code的轨迹内容"); + + var res = new UnifyResultDto(true) + { + Data = new GetTrackContentByCodeOutput + { + Content = content.Content, + EnContent = content.EnContent, + IsExternal = content.IsExternal + } + }; + + return res; + } + + /// + /// 创建轨迹时获取可用的轨迹内容 + /// + /// + /// + [HttpPost("GetAvailableContent")] + public async Task>> GetAvailableContent(GetAvailableContentInput input) + { + if (input.SystemId <= 0) + return new UnifyResultDto>(false, "系统id需大于0!"); + + if (string.IsNullOrEmpty(input.OrderNo)) + return new UnifyResultDto>(false, "单号不能为空!"); + + //获取当前订单下已有的轨迹内容 + var orderId = await _orderRepository.GetFirstAsync(x => x.OrderNo == input.OrderNo && x.SubSystemId == input.SystemId, x => x.Id); + if (orderId == default) + throw new BusinessException(message: "订单不存在!"); + + //获取轨迹详情 + var trackDetails = await _trackDetailsEsRepository.GetListAsync(orderId); + + + //获取当前子系统下所有的轨迹内容 + var contentList = await _trackContentRepository.GetListBySystemIdAsync(input.SystemId); + if (contentList == null) + throw new BusinessException(message: "当前子系统下未找到任何可用的轨迹内容!"); + + + var res = new UnifyResultDto>(true) + { + Data = new List() + }; + + foreach (var item in contentList) + { + if (!item.IsRepeatable && trackDetails?.Any(m => m.TrackCode == item.Code) == true) //跳过已存在轨迹内容 + continue; + + if (!item.IsAllowManuallyCreate && input.TrackOptionType == TrackOptionType.创建) //跳过不允许手动创建的轨迹内容 + continue; + + if (!item.IsAllowManuallyUpdate && input.TrackOptionType == TrackOptionType.修改) //跳过不允许手动创建的轨迹内容 + continue; + + res.Data.Add(new GetAvailableContentOutput() + { + IsExternal = item.IsExternal, + EnContent = item.EnContent, + Content = item.Content, + Code = item.Code, + Id = item.Id + }); + } + + return res; + } + #region 私有方法 private async Task AddAsync(EditTrackContentInput input) diff --git a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs index 7c7950dd..b1fff209 100644 --- a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs +++ b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs @@ -4,6 +4,7 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.Order; namespace SJZY.Track.Application.Services.TrackOrders; @@ -18,6 +19,7 @@ public class TrackOrderService : ApplicationService private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; private readonly IOrderRepository _orderRepository; private readonly ITrackContentRepository _trackContentRepository; + private readonly ITrackStatusRepository _trackStatusRepository; private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; @@ -26,13 +28,15 @@ public class TrackOrderService : ApplicationService ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository, ITrackPushRecordEsRepository trackPushRecordEsRepository, - IOrderOperationRecordEsRepository orderOperationRecordEsRepository) + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + ITrackStatusRepository trackStatusRepository) { _orderRepository = orderRepository; _trackDetailsEsRepository = trackDetailsEsRepository; _trackContentRepository = trackContentRepository; _trackPushRecordEsRepository = trackPushRecordEsRepository; _orderOperationRecordEsRepository = orderOperationRecordEsRepository; + _trackStatusRepository = trackStatusRepository; } #region 轨迹订单列表 @@ -164,6 +168,73 @@ public class TrackOrderService : ApplicationService return list; } + + /// + /// 按时间轴获取轨迹内容 + /// + /// + /// + [HttpPost("GetDetailTimeline")] + public async Task>> GetDetailTimeline(GetDetailTimelineInput input) + { + var res = new UnifyResultDto>(true); + + var order = await _orderRepository.GetFirstAsync(m => m.OrderNo == input.OrderNumber); + if (order == null) + return new UnifyResultDto>(false, "订单不存在"); + + if (input.SystemId <= 0) + return new UnifyResultDto>(false, "子系统id不合法"); + + var trackStatus = await _trackStatusRepository.GetListAsync(m => m.SubSystemId == input.SystemId); + + var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); + res.Data = new List(); + var isCompleted = false; + foreach (var item in trackDetails) + { + //是否完结 + isCompleted = trackStatus.Any(m => m.IsCompleted && m.Code == item.TrackStatus); + + + + res.Data.Add(new GetDetailTimelineOutput() + { + IsHighlight = true, + Files = new List(), + //Remark = item.Remark, + //TrackTimeZone = item.TrackTimeZone, + TrackTime = ToUnixTimestamp(item.TrackTime), + TrackPlace = item.TrackPlace, + EnContent = item.TrackEnContent, + Content = item.TrackContent, + TrackCode = item.TrackCode + }); + } + + //如果轨迹状态没完结则追加最后一个默认节点 + if (!isCompleted) + { + res.Data.Add(new GetDetailTimelineOutput() + { + Content = "签收", + IsHighlight = false, + TrackTimeZone = $"GMT{(order.DestinationTimeZone >= 0 ? "+" : "-")}{order.DestinationTimeZone}", + TrackTime = ToUnixTimestamp(order.EstimatedDeliveryDate), + TrackTimePrefix = "预计签收时间:", + }); + } + + return res; + } + + public static long ToUnixTimestamp(DateTime time) + { + //var sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + var sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local); + return (long) (time - sTime).TotalMilliseconds; + } + /// /// 根据轨迹id删除单条轨迹 /// diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index 9a24699e..492555ec 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -172,6 +172,18 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot [SugarColumn(IsIgnore = true)] public List OrderPullStatus { get; set; } + /// + /// 目的地时区 + /// + [SugarColumn(ColumnName = "DestinationTimeZone")] + public float DestinationTimeZone { get; set; } + + /// + /// 预计到达时间 + /// + [SugarColumn(ColumnName = "EstimatedDeliveryDate")] + public DateTime EstimatedDeliveryDate { get; set; } + public void ResetTrackInfo() { IsCompleted = false; diff --git a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs index 000dbe3b..b321e87b 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs @@ -26,4 +26,6 @@ public interface ITrackContentRepository : IBasicRepository Expression> whereExpression); Task GetTemplateIsExist(int trackContentId); + Task GetByCodeAsync(int systemId, string code); + Task> GetListBySystemIdAsync(int systemId); } diff --git a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs index ee797ce1..d5b41963 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs @@ -36,6 +36,12 @@ public class TrackContentEntity : IFullAuditedBasicEntitys, IAggregateRoot [SugarColumn(ColumnName = "SubSystemId")] public int SubSystemId { get; set; } + /// + /// 子系统名称 + /// + [SugarColumn(IsIgnore = true)] + public string SubSystem { get; set; } + /// /// 轨迹标记id,多个逗号分隔 /// @@ -53,4 +59,28 @@ public class TrackContentEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "IsExternal")] public bool IsExternal { get; set; } + + /// + /// 是否可重复 + /// + [SugarColumn(ColumnName = "IsRepeatable")] + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + [SugarColumn(ColumnName = "IsAllowManuallyUpdate")] + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + [SugarColumn(ColumnName = "IsAllowManuallyCreate")] + public bool IsAllowManuallyCreate { get; set; } + + /// + /// 是否同步轨迹订单上的预计到达时间 + /// + [SugarColumn(ColumnName = "IsChangeOrderEdd")] + public bool IsChangeOrderEdd { get; set; } } diff --git a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs index c1399c6a..a4fe71cd 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs @@ -113,7 +113,6 @@ public class TrackContentRepository : BasicRepository, ITrac return false; } - public async Task> GetMapPageAsync( GetTrackContentMapPageInputVO input) { @@ -220,4 +219,27 @@ public class TrackContentRepository : BasicRepository, ITrac return await Context.Updateable().SetColumns(columns).Where(whereExpression) .ExecuteCommandAsync() > 0; } + + public Task GetByCodeAsync(int systemId, string code) + { + return Context.Queryable().FirstAsync(m => m.SubSystemId == systemId && m.Code == code); + } + + public Task> GetListBySystemIdAsync(int systemId) + { + return Context.Queryable() + .Where(content => content.SubSystemId == systemId && !content.IsDeleted) + .Select((content) => new TrackContentEntity + { + Id = content.Id, + Code = content.Code, + IsExternal = content.IsExternal, + EnContent = content.EnContent, + Content = content.Content, + IsRepeatable = content.IsRepeatable, + IsAllowManuallyCreate = content.IsAllowManuallyCreate, + IsAllowManuallyUpdate = content.IsAllowManuallyUpdate, + }) + .ToListAsync(); + } }