using System.Linq.Expressions; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Expand.AliyunOSS; 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.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Dtos.TrackContents; using SJZY.Track.Domain.Dtos.TrackTemplate; using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.TrackContents; /// /// 轨迹内容服务 /// [ApiExplorerSettings(GroupName = "轨迹内容")] [Route("/Track/Content")] public class TrackContentService : ApplicationService { private readonly IStringLocalizer _stringLocalizer; private readonly ITrackContentRepository _trackContentRepository; private readonly ITrackTemplateRepository _trackTemplateRepository; 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, IOrderRepository orderRepository, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackTemplateRepository trackTemplateRepository) { _stringLocalizer = stringLocalizer; _trackContentRepository = trackContentRepository; _trackStatusBasicQuery = trackStatusBasicQuery; _trackFlagBasicQuery = trackFlagBasicQuery; _orderRepository = orderRepository; _trackDetailsEsRepository = trackDetailsEsRepository; _trackTemplateRepository = trackTemplateRepository; } /// /// 轨迹内容编辑 /// /// [HttpPost("Edit")] public async Task EditAsync(EditTrackContentInput input) { if (input.TrackStatusId != null) { if (!await _trackStatusBasicQuery.IsAnyAsync(x => x.SubSystemId == input.SubSystemId && x.Id == input.TrackStatusId)) { throw new BusinessException(message: "轨迹状态不存在"); } } if (!input.TrackFlagIds.IsNullOrEmpty()) { var counter = await _trackFlagBasicQuery.CountAsync(x => x.SubSystemId == input.SubSystemId && input.TrackFlagIds!.Contains(x.Id)); if (counter != input.TrackFlagIds!.Length) { throw new BusinessException(message: "存在非法轨迹标记"); } } return input.Options switch { OptionType.新增 => await AddAsync(input), OptionType.修改 => await UpdateAsync(input), OptionType.删除 => await DeleteAsync(input), _ => throw new BusinessException(message: "当前操作动作不合法") }; } /// /// 根据内容id获取轨迹内容 /// /// /// [HttpGet("GetDetail")] public async Task> GetDetailAsync(int id) { var detailInfo = await _trackContentRepository.GetDetailAsync(id); if (detailInfo == null) { return new UnifyResultDto(false, null!, "未查询到轨迹状态"); } var dto = ObjectMapper.Map(detailInfo); return new UnifyResultDto(GlobalConst.SuccessCode, "", dto); } /// /// 获取分页轨迹内容 /// /// /// [HttpPost("GetList")] public async Task> GetPageTrackContent(GetPageTrackContentInput input) { var vo = ObjectMapper.Map(input); var resultDto = await _trackContentRepository.GetPageTrackContent(vo); var pageResultDto = ObjectMapper.Map, UnifyPageResultDto>( resultDto); return pageResultDto; } /// /// 轨迹内容映射列表 /// /// /// [HttpPost("GetMapPage")] public async Task> GetMapPageAsync( [FromBody] GetTrackContentMapPageInputVO input) { return await _trackContentRepository.GetMapPageAsync(input); } /// /// 轨迹内容映射详情 /// /// /// [HttpGet("GetMapDetail")] public async Task GetMapDetailAsync(int id) { return await _trackContentRepository.GetMapDetailAsync(id); } /// /// 轨迹内容映射编辑 /// /// /// [HttpPost("EditMap")] public async Task EditMapAsync([FromBody] EditTrackContentMapInput input) { if (input.Options != OptionTypeNoNull.删除) { if (input.SubSystemId == input.MapSubSystemId) throw new BusinessException(message: _stringLocalizer["NotAllowedToMapSubSystem"]); Expression> isMapAnyExp = x => x.TrackContentId == input.TrackContentId && x.MapTrackContentId == input.MapTrackContentId; if (input.Options == OptionTypeNoNull.修改) isMapAnyExp.And(x => x.Id != input.Id); if (await _trackContentRepository.IsMapAnyAsync(isMapAnyExp)) throw new BusinessException(message: _stringLocalizer["IsTrackContentMapAny"]); } switch (input.Options) { case OptionTypeNoNull.新增: var trackContentMapEntity = ObjectMapper.Map(input); await _trackContentRepository.InsertMapAsync(trackContentMapEntity); break; case OptionTypeNoNull.修改: var oldTrackContentMapEntity = await _trackContentRepository.GetMapByIdAsync(input.Id!.Value) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); ObjectMapper.Map(input, oldTrackContentMapEntity); await _trackContentRepository.UpdateMapAsync(oldTrackContentMapEntity); break; case OptionTypeNoNull.删除: await _trackContentRepository.SoftDeleteMapAsync(x => x.Id == input.Id); break; default: throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackContentMapInput.Options)]); } 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; } /// /// 根据子系统id、单号、订单类型、轨迹发生时间、轨迹code获取轨迹内容 /// /// /// [HttpPost("GetContentDetail")] public async Task> GetContentDetail([FromBody] GetContentDetailInput input) { if (input.SystemId <= 0) return new UnifyResultDto(false, "子系统Id必须大于等于0"); if (string.IsNullOrEmpty(input.TrackCode)) return new UnifyResultDto(false, "轨迹内容code不能为空"); if (string.IsNullOrEmpty(input.OrderNumber)) return new UnifyResultDto(false, "订单code不能为空"); if (input.OrderType <= 0) return new UnifyResultDto(false, "订单类型不能为空"); if (input.TrackTime == default) return new UnifyResultDto(false, "轨迹发生时间不能为空"); var content = await _trackDetailsEsRepository.GetDetailAsync(input.OrderNumber, input.TrackCode, input.OrderType, input.SystemId, input.TrackTime); if (content == default) return new UnifyResultDto(false, "在当前子系统中未找到指定code的轨迹内容"); var res = new UnifyResultDto(true) { Data = ObjectMapper.Map(content) }; if (res.Data != default && res.Data.Files.Any()) { foreach (var item in res.Data.Files) { item.Url = OSSHelper.GetUrlByKey(item.OssKey); } } 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 order = await _orderRepository.GetFirstAsync(x => x.OrderNo == input.OrderNo && x.SubSystemId == input.SystemId); if (order == default) throw new BusinessException(message: "订单不存在!"); //获取轨迹详情 var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); //获取当前子系统下所有的轨迹内容 var contentList = await _trackContentRepository.GetListBySystemIdAsync(input.SystemId); if (contentList == null) throw new BusinessException(message: "当前子系统下未找到任何可用的轨迹内容!"); //如果订单给了获取模板code,则进一步根据模板code进行过滤 if (!string.IsNullOrEmpty(order.TemplateCodes)) { var currentCodes = order.TemplateCodes.Split(","); var template = await _trackTemplateRepository.GetContentByTemplateCodes(currentCodes, input.SystemId); contentList = contentList.Where(m => template.Contains(m.Code)).ToList(); } var res = new UnifyResultDto>(true) { Data = new List() }; foreach (var item in contentList) { //新增时跳过已存在轨迹内容 if (input.TrackOptionType == TrackOptionType.创建 && !item.IsRepeatable && trackDetails?.Any(m => m.TrackCode == item.Code) == true) continue; // 修改时跳过不存在轨迹内容 if (input.TrackOptionType == TrackOptionType.修改 && trackDetails != null && trackDetails.All(m => m.TrackCode != item.Code)) 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 }); } if (input.TrackOptionType == TrackOptionType.创建 || trackDetails == null || trackDetails.Count == 0) { return res; } //修改操作,查轨迹内容列表反映明细表数据,重新构造响应数据 var matchContent = new List(); var contents = res.Data.Select(x => new { x.Id, x.IsExternal, x.Code }); foreach (var content in contents) { var match = trackDetails .Where(x => x.TrackCode == content.Code) .Select(matchItem => new GetAvailableContentOutput { IsExternal = content.IsExternal, Id = content.Id, EnContent = matchItem.TrackEnContent, Content = matchItem.TrackContent, Code = matchItem.TrackCode, TrackPlace = matchItem.TrackPlace, TrackTime = matchItem.TrackTime, TrackTimeZone = matchItem.TrackTimeZone, Source = matchItem.Source, DestinationTimeZone = matchItem.DestinationTimeZone, EstimatedDeliveryDate = matchItem.EstimatedDeliveryDate, TrackPlacePostcode = matchItem.TrackPlacePostcode, TrackPlaceNation = matchItem.TrackPlaceNation, TrackPlaceNationId = matchItem.TrackPlaceNationId, TrackPlaceProvince = matchItem.TrackPlaceProvince, TrackPlaceProvinceId = matchItem.TrackPlaceProvinceId, TrackPlaceCity = matchItem.TrackPlaceCity, TrackPlaceCityId = matchItem.TrackPlaceCityId, Remarks = matchItem.Remarks, TrackTimeZoneValue = matchItem.DestinationTimeZone, IsVisibility = matchItem.IsVisibility, FileItems = matchItem.Files?.Select(x => new FileItemDto { FileName = x.FileName, OssKey = x.OssKey }).ToList() }); matchContent.AddRange(match); } res.Data = matchContent; return res; } #region 私有方法 private async Task AddAsync(EditTrackContentInput input) { #region 业务逻辑校验 var trackContentEntitys = await _trackContentRepository.GetListAsync(a => a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Content == input.Content || a.EnContent == input.EnContent)); if (trackContentEntitys.Any()) { var codes = trackContentEntitys.FirstOrDefault(a => a.Code == input.Code); if (codes != null) { throw new BusinessException(message: "该子系统下轨迹代码已存在"); } var contents = trackContentEntitys.FirstOrDefault(a => a.Content == input.Content); if (contents != null) { throw new BusinessException(message: "该子系统下轨迹内容已存在"); } var contentEns = trackContentEntitys.FirstOrDefault(a => a.EnContent == input.EnContent); if (contentEns != null) { throw new BusinessException(message: "该子系统下轨迹内容英文已存在"); } } #endregion 业务逻辑校验 var entity = ObjectMapper.Map(input); entity.TrackFlagId = input.TrackFlagIds?.JoinAsString(","); var isTrue = await _trackContentRepository.InsertAsync(entity); return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue); } private async Task UpdateAsync(EditTrackContentInput input) { #region 业务逻辑校验 var trackContentEntities = await _trackContentRepository.GetListAsync( a => a.Id != input.Id && a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Content == input.Content || a.EnContent == input.EnContent)); if (trackContentEntities.Any()) { var codes = trackContentEntities.FirstOrDefault(a => a.Code == input.Code); if (codes != null) { throw new BusinessException(message: "该子系统下轨迹代码已存在"); } var contents = trackContentEntities.FirstOrDefault(a => a.Content == input.Content); if (contents != null) { throw new BusinessException(message: "该子系统下轨迹内容已存在"); } var contentEns = trackContentEntities.FirstOrDefault(a => a.EnContent == input.EnContent); if (contentEns != null) { throw new BusinessException(message: "该子系统下轨迹内容英文已存在"); } } #endregion 业务逻辑校验 //更新的时候需要覆盖内容映射轨迹代码 var trackContent = await _trackContentRepository.GetFirstAsync(a => a.Id == input.Id); if (trackContent == null) { throw new BusinessException(message: "轨迹内容不存在"); } bool isTrue; using (var ts = TransactionScopeHelper.Create()) { // 如果轨迹内容的子系统和code发生变化,同步到轨迹映射表 if (trackContent.SubSystemId != input.SubSystemId || trackContent.Code != input.Code) { await _trackContentRepository.UpdateMapAsync( x => new TrackContentMapEntity { SubSystemId = input.SubSystemId, TrackContentCode = input.Code }, x => x.TrackContentId == input.Id); await _trackContentRepository.UpdateMapAsync( x => new TrackContentMapEntity { MapSubSystemId = input.SubSystemId, MapTrackContentCode = input.Code }, x => x.MapTrackContentId == input.Id); } ObjectMapper.Map(input, trackContent); trackContent.TrackFlagId = input.TrackFlagIds?.JoinAsString(","); isTrue = await _trackContentRepository.UpdateAsync(trackContent); ts.Complete(); } return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue); } private async Task DeleteAsync(EditTrackContentInput input) { #region 业务校验 //查询是否关联了轨迹模版内容 var isExistTemplate = await _trackContentRepository.GetTemplateIsExist(input.Id); if (isExistTemplate) { throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除"); } //var trackTemplateContents = await _trackTemplateContentBasicQuery.GetListAsync(a => a.TrackContentId == input.Id); //if (trackTemplateContents.Any()) //{ // throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除"); //} //需要加个判断,存在内容映射,则出提示 //var trackContentMapEntities = await _trackContentMapBasicQuery.GetListAsync(a => a.TrackContentId == input.Id || a.MapTrackContentId == input.Id); //if (trackContentMapEntities.Any()) //{ // throw new BusinessException(message: "无法删除该内容,该轨迹内容已在轨迹内容映射中使用了,请检查"); //} #endregion 业务校验 var isTrue = await _trackContentRepository.SoftDeleteAsync(x => x.Id == input.Id); return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", isTrue); } #endregion 私有方法 }