using System.Linq.Expressions; using SJZY.Expand.AliyunOSS; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackOrder; 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; /// /// 轨迹订单服务 /// [ApiExplorerSettings(GroupName = "轨迹订单")] [Route("/Track/Order")] 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; public TrackOrderService( IOrderRepository orderRepository, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository, ITrackPushRecordEsRepository trackPushRecordEsRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, ITrackStatusRepository trackStatusRepository) { _orderRepository = orderRepository; _trackDetailsEsRepository = trackDetailsEsRepository; _trackContentRepository = trackContentRepository; _trackPushRecordEsRepository = trackPushRecordEsRepository; _orderOperationRecordEsRepository = orderOperationRecordEsRepository; _trackStatusRepository = trackStatusRepository; } #region 轨迹订单列表 /// /// 获取分页的轨迹订单 /// /// /// [HttpPost("GetTrackOrderList")] public async Task> GetTrackOrderPagedList(GetPageTrackOrderInput input) { var vo = ObjectMapper.Map(input); var pageList = await _orderRepository.GetTrackOrderPagedList(vo); var pageResultDto = ObjectMapper.Map, UnifyPageResultDto>(pageList); return pageResultDto; } #endregion /// /// 更新订单状态 /// /// /// /// [HttpPost("UpdateOrderStatus")] public async Task UpdateOrderStatus(UpdateOrderStatusInput input) { var order = await _orderRepository.GetFirstAsync(x => x.Id == input.OrderId); if (order == default) throw new BusinessException(message: "订单不存在"); order.IsCompleted = input.IsCompleted; return await _orderRepository.UpdateColumnAsync(order, x => new { x.IsCompleted }); } /// /// 获取轨迹推送记录 /// /// /// 订单id [HttpGet("GetTrackPushRecords")] public async Task> GetTrackPushRecordsAsync(int orderId) { var records = await _trackPushRecordEsRepository.GetTrackPushRecordsAsync(orderId); var res = ObjectMapper.Map, List>(records); res.ForEach(x => { int hours = (int) x.TrackTimeZone; // 提取整数部分作为小时 int minutes = (int) ((x.TrackTimeZone - hours) * 60); // 将小数部分乘以 60 转换为分钟 x.TrackGTMTimeZone = $"GMT {(x.TrackTimeZone >= 0 ? "+" : "-")}{new TimeSpan(hours, minutes, 0).ToString().RemovePostFix(":00")}"; }); return res; } /// /// 根据订单id获取轨迹明细列表 /// /// /// /// /// [HttpPost("GetDetails")] public async Task> GetTracksAsync(int? orderId, string? orderNo, int? systemId) { Expression>? whereExpression = null; //根据订单id查询 if (orderId != null && orderId > 0) whereExpression = m => m.Id == orderId; //根据订单号+系统id查询 if (!string.IsNullOrEmpty(orderNo) && systemId != null && systemId > 0) whereExpression = m => m.OrderNo == orderNo && m.SubSystemId == systemId; if (whereExpression == default) throw new BusinessException(message: "请求参数异常"); var order = await _orderRepository.GetFirstAsync(whereExpression); if (order == default) { throw new BusinessException(message: "订单不存在"); } var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); if (trackDetails.IsNullOrEmpty()) { return new List(); } var list = ObjectMapper.Map, List>(trackDetails); // 计算时区 list.ForEach(a => { if (a.TrackTimeZoneValue == 0f) { a.TrackTimeZone = "GMT +00:00"; } else if (Math.Abs(a.TrackTimeZoneValue - GlobalConst.NoneTrackTimeZone) < 1) { a.TrackTimeZone = "--"; } else { // 将小数形式的小时转换为时区偏移量 var hours = (int) a.TrackTimeZoneValue; // 提取整数部分作为小时 var minutes = (int) ((a.TrackTimeZoneValue - hours) * 60); // 将小数部分乘以 60 转换为分钟 var offset = new TimeSpan(hours, minutes, 0); var timeZoneStr = offset.ToString(); var flag = a.TrackTimeZoneValue > 0f ? "+" : ""; a.TrackTimeZone = $"GMT {flag}{timeZoneStr.RemovePostFix(":00")}"; } }); 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不合法"); if (input.CurrenUserSystemId <= 0) return new UnifyResultDto>(false, "当前登陆用户子系统id不合法"); var system = await _orderRepository.GetSystemInfoById(input.CurrenUserSystemId); if (system == null) return new UnifyResultDto>(false, "未找到指定id的子系统"); var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); //时间轴不显示轨迹内容为空的轨迹,进行过滤 trackDetails = trackDetails.Where(x => !x.TrackContent.IsNullOrWhiteSpace() && x.TrackContent != GlobalConst.EmptyString).ToList(); res.Data = new List(); foreach (var item in trackDetails) { //如果是外部系统,且轨迹内容不对外则跳过这条轨迹内容 if (system.SystemProperty == 2 && !item.IsExternal) continue; //时间和时区任意一个为空则使用创建时间做为排序参照值 var timeTick = ToUnixTimestamp((item.TrackTime == null || Math.Abs(item.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1) ? item.CreateTime : item.TrackTime); res.Data.Add(new GetDetailTimelineOutput() { IsHighlight = true, IsShowHover = true, Remark = item.Remarks == null || item.Remarks == "--" ? "" : item.Remarks, TrackTimeZone = $"GMT{(item.TrackTimeZone >= 0 ? "+" : "-")}{GetTimeZoneStr(item.TrackTimeZone)}", TrackTime = timeTick, TrackPlace = item.TrackPlace, EnContent = item.TrackEnContent, Files = item.Files == null ? new List() : item.Files!.Select(m => new TrackFileItem() { OssKey = m.OssKey, FileName = m.FileName, Url = m.OssKey.GetUrlByKey(), }).ToList(), Content = item.TrackContent, TrackCode = item.TrackCode, TrackPlaceNation = item.TrackPlaceNation, TrackPlaceProvince = item.TrackPlaceProvince, TrackPlaceCity = item.TrackPlaceCity, }); } // 按轨迹发生时间正序排序 res.Data = res.Data.OrderBy(m => m.TrackTime).ToList(); if (!order.IsCompleted) //如果没完结则显示签收节点 { var eddUnixTimestamp = order.EstimatedDeliveryDate.HasValue ? ToUnixTimestamp(DateTime.Parse(order.EstimatedDeliveryDate.ToString()!)) : 0; var isShowTime = eddUnixTimestamp > 0 && res.Data.All(m => m.TrackTime < eddUnixTimestamp); //当存在需要显示的轨迹才需要补充签收节点 if (res.Data.Count != 0) { res.Data.Add(new GetDetailTimelineOutput() { Content = "签收", IsHighlight = false, TrackTimeZone = isShowTime ? $"GMT{(order.DestinationTimeZone >= 0 ? "+" : "-")}{order.DestinationTimeZone}" : "", TrackTime = isShowTime ? eddUnixTimestamp : 0, TrackTimePrefix = isShowTime ? "预计签收时间:" : "", }); } } return res; } public static long ToUnixTimestamp(DateTime time) { var sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local); return (long) (time - sTime).TotalMilliseconds; } private string GetTimeZoneStr(float timeZone) { var time = timeZone.ToString().Split('.'); if (time.Length > 1 && time[1] != "0") //如果时区有小数点 { return time[0] + ":30"; } else { return time[0] + ":00"; } } /// /// 根据轨迹id删除单条轨迹 /// /// 轨迹id /// [HttpPost("DeleteTrackById")] public async Task DeleteTrackByIdAsync(string trackId) { var track = await _trackDetailsEsRepository.GetByIdAsync(trackId); // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (track == null) { throw new BusinessException(message: "轨迹不存在!"); } await _trackDetailsEsRepository.DeleteTrackByIdAsync(trackId, track.IndexName); return true; } /// /// 根据订单id查询订单操作记录 /// /// 订单id /// [HttpGet("GetOrderOperationsById")] public async Task> GetOrderOperationsByIdAsync(int orderId) { return await _orderOperationRecordEsRepository.GetOrderOperationsByIdAsync(orderId); } }