using System.Linq.Expressions; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; using TrackCenter.Application.Dtos.TrackPush; using TrackCenter.Application.Services; using TrackCenter.Application.Helpers; using TrackCenter.Application.Localization; using TrackCenter.Application.Services.Warning.Handlers; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackPushAggregate; using TrackCenter.Domain.Dtos.TrackPush; using TrackCenter.Domain.Enums; using Volo.Abp.DependencyInjection; namespace TrackCenter.Application.Services.TrackPush; /// /// 轨迹推送 /// [ApiExplorerSettings(GroupName = "轨迹推送")] [Route("/Track/PushConfig")] public class TrackPushService : ApplicationServiceBase, ISingletonDependency { private readonly IStringLocalizer _stringLocalizer; private readonly ITrackPushCacheService _trackPushCacheService; private readonly ITrackPushConfigRepository _trackPushConfigRepository; private readonly IOrderRepository _orderRepository; private readonly IServiceProvider _serviceProvider; public TrackPushService( IStringLocalizer stringLocalizer, ITrackPushConfigRepository trackPushConfigRepository, ITrackPushCacheService trackPushCacheService, IOrderRepository orderRepository, IServiceProvider serviceProvider) { _stringLocalizer = stringLocalizer; _trackPushConfigRepository = trackPushConfigRepository; _trackPushCacheService = trackPushCacheService; _orderRepository = orderRepository; _serviceProvider = serviceProvider; } /// /// 轨迹推送配置列表 /// /// /// [HttpPost("GetPage")] public async Task> GetPageAsync([FromBody] KeywordsInputVO input) { return await _trackPushConfigRepository.GetPageAsync(input); } /// /// 获取推送配置类型标签卡列表 /// /// [HttpPost("GetConfigTags")] public async Task> GetConfigTags([FromBody] GetConfigTagsInputVO inputVo) { var orderTypes = await _trackPushConfigRepository.GetConfigTags(inputVo); if (orderTypes.Count == 0) return new List(); var trackOrderTypes = await _orderRepository.GetTrackOrderTypeDictAsync(); return orderTypes.Select(x => new TrackPushConfigTagDto { Type = x, Name = trackOrderTypes[x.ToString()] }) .OrderBy(x => x.Type) .ToList(); } /// /// 轨迹推送配置内容列表 /// /// /// [HttpPost("GetContentPage")] public async Task> GetContentPageAsync( [FromBody] GetTrackPushContentPageInputVO input) { return await _trackPushConfigRepository.GetContentPageAsync(input); } /// /// 轨迹推送配置详情 /// /// /// [HttpGet("GetDetail")] public async Task GetDetailAsync(int id) { return await _trackPushConfigRepository.GetDetailAsync(id); } /// /// 轨迹推送配置内容详情 /// /// /// [HttpGet("GetContentDetail")] public async Task GetContentDetailAsync(int id) { return await _trackPushConfigRepository.GetContentDetailAsync(id); } /// /// 轨迹推送配置编辑 /// /// /// [HttpPost("Edit")] public async Task EditAsync([FromBody] EditTrackPushConfigInput input) { if (input.Options != OptionTypeNoNull.删除) { Expression> isAnyExp = x => x.SubSystemId == input.SubSystemId && x.CustomId == input.CustomId; if (input.Options == OptionTypeNoNull.修改) isAnyExp = isAnyExp.And(x => x.Id != input.Id); if (await _trackPushConfigRepository.IsAnyAsync(isAnyExp)) throw new BusinessException(message: _stringLocalizer["IsTrackPushConfigAny"]); } var msg = string.Empty; if (input.Options is OptionTypeNoNull.新增 or OptionTypeNoNull.修改) { var (success, message) = CheckDateTimeFormat(input.DateTimeFormat, input.DateTimeFormatType, input.TimezoneFormat); if (!success) throw new BusinessException(message: message); msg = message; } using var ts = TransactionScopeHelper.Create(); switch (input.Options) { case OptionTypeNoNull.新增: var trackPushEntity = ObjectMapper.Map(input); await _trackPushConfigRepository.InsertReturnIdentityAsync(trackPushEntity); await _trackPushCacheService.SetPushContentConfigsAsync(trackPushEntity.SubSystemId, trackPushEntity.CustomId); break; case OptionTypeNoNull.修改: var oldTrackPushEntity = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); ObjectMapper.Map(input, oldTrackPushEntity); await _trackPushConfigRepository.UpdateAsync(oldTrackPushEntity); await _trackPushCacheService.SetPushContentConfigsAsync(oldTrackPushEntity.SubSystemId, oldTrackPushEntity.CustomId); break; case OptionTypeNoNull.删除: var entity = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); await _trackPushConfigRepository.SoftDeleteAsync(x => x.Id == input.Id); await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.TrackPushConfigId == input.Id); await _trackPushCacheService.SetPushContentConfigsAsync(entity.SubSystemId, entity.CustomId); break; default: throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackPushConfigInput.Options)]); } ts.Complete(); return msg; } /// /// 获取服务商code根据客户id /// /// /// [HttpGet("GetServiceCodeByCustomerId")] public async Task GetServiceCodeByCustomerId(int customerId) { return await _trackPushConfigRepository.GetServiceCodeByCustomerIdAsync(customerId); } /// /// 轨迹推送配置内容编辑 /// /// /// [HttpPost("EditContent")] public async Task EditContentAsync([FromBody] EditTrackPushContentInput input) { if (input.Options != OptionTypeNoNull.删除) { Expression> isContentAnyExp = x => x.TrackPushConfigId == input.TrackPushConfigId && x.OrderNoType == input.OrderNoType; if (input.Options == OptionTypeNoNull.修改) isContentAnyExp = isContentAnyExp.And(x => x.Id != input.Id); if (await _trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => x.TrackContentId == input.TrackContentId))) throw new BusinessException(message: _stringLocalizer["IsTrackPushContentAny"]); if (!input.TrackContentCodeValue.IsNullOrWhiteSpace() && await _trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => x.TrackContentCodeValue == input.TrackContentCodeValue))) throw new BusinessException(message: _stringLocalizer["IsTrackPushContentCodeValueAny"]); if (!input.TrackStatusValue.IsNullOrWhiteSpace() && await _trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => x.TrackStatusValue == input.TrackStatusValue))) throw new BusinessException(message: _stringLocalizer["IsTrackPushContentStatusValueAny"]); if (!input.TrackContentValue.IsNullOrWhiteSpace() && await _trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => x.TrackContentValue == input.TrackContentValue))) throw new BusinessException(message: _stringLocalizer["IsTrackPushContentValueAny"]); if (!input.TrackEnContentValue.IsNullOrWhiteSpace() && await _trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => x.TrackEnContentValue == input.TrackEnContentValue))) throw new BusinessException(message: _stringLocalizer["IsTrackPushEnContentValueAny"]); } var trackPushConfigId = input.TrackPushConfigId; using var ts = TransactionScopeHelper.Create(); TrackPushContentConfigEntity? oldContentConfig = null; TrackPushContentConfigEntity? postContentConfig = null; switch (input.Options) { case OptionTypeNoNull.新增: { var maxSort = await _trackPushConfigRepository.ContentMaxAsync(x => x.Sort, x => x.OrderNoType == input.OrderNoType && x.TrackPushConfigId == input.TrackPushConfigId ); var entity = ObjectMapper.Map(input); entity.Sort = maxSort + 1; await _trackPushConfigRepository.InsertContentAsync(entity); break; } case OptionTypeNoNull.修改: { var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); oldContentConfig = entity.DeepCopy(); ObjectMapper.Map(input, entity); await _trackPushConfigRepository.UpdateContentAsync(entity); postContentConfig = entity; break; } case OptionTypeNoNull.删除: { var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); oldContentConfig = entity; trackPushConfigId = entity.TrackPushConfigId; await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id); await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1, x => x.OrderNoType == entity.OrderNoType && x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort ); break; } default: throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackPushContentInput.Options)]); } var pushConfig = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == trackPushConfigId); if (pushConfig != null) { await _trackPushCacheService.SetPushContentConfigsAsync(pushConfig.SubSystemId, pushConfig.CustomId); } ts.Complete(); // 引发预警计算 WarningCalc_PushContentConfigChanged(pushConfig, oldContentConfig, postContentConfig); return true; } /// /// 轨迹推送配置内容排序 /// /// /// [HttpPost("SortContent")] public async Task SortContentAsync([FromBody] SortTrackPushContentInput input) { var ids = input.SortInfo.Select(x => int.Parse(x.Key)).ToList(); var trackPushContentEntities = await _trackPushConfigRepository.GetContentListAsync(x => ids.Contains(x.Id)); trackPushContentEntities.ForEach(item => { item.Sort = input.SortInfo.Single(x => x.Key == item.Id.ToString()).Value; }); if (trackPushContentEntities.Count > 0) { using var ts = TransactionScopeHelper.Create(); await _trackPushConfigRepository.UpdateContentRangeAsync(trackPushContentEntities); var pushConfig = await _trackPushConfigRepository.GetFirstAsync( x => x.Id == trackPushContentEntities[0].TrackPushConfigId, y => new { y.SubSystemId, y.CustomId }); if (pushConfig != null) { await _trackPushCacheService.SetPushContentConfigsAsync(pushConfig.SubSystemId, pushConfig.CustomId); } ts.Complete(); } return true; } private void WarningCalc_PushContentConfigChanged(TrackPushConfigEntity? pushConfig, TrackPushContentConfigEntity? oldContentConfig, TrackPushContentConfigEntity? postContentConfig) { // 推送配置主体不存在? if (pushConfig == null) return; // 说明是新增 if (oldContentConfig == null) return; // 删除 postContentConfig == null 否则为更新(tips:判断更新差异化比较?) var contentConfigEntity = postContentConfig ?? oldContentConfig; _ = Task.Run(async () => { var scope = _serviceProvider.CreateScope(); try { var handler = scope.ServiceProvider.GetRequiredService(); await handler.PushConfigChangedHandleAsync(pushConfig, contentConfigEntity); } catch (Exception ex) { LogHelper.Error(ex); } finally { scope.Dispose(); } }); } private static (bool Success, string Message) CheckDateTimeFormat(string? dateTimeFormat, int? dateTimeFormatType, string? timezoneFormat) { const int defaultTimeZone = 8; var dateTime = DateTime.Now; string dateStr; try { if (dateTimeFormatType == (int) DateTimeFormatEnum.Timestamp) { dateStr = DateTimeHelper.ConvertToUnixTimestamp(dateTime).ToString(); return (true, $"格式化样例:{dateStr}"); } if (dateTimeFormatType == (int) DateTimeFormatEnum.DateTimeAndTimezone) { // 没时间有时区,出错 if (string.IsNullOrWhiteSpace(dateTimeFormat) && !string.IsNullOrWhiteSpace(timezoneFormat)) return (false, "如果填写了时区格式,那么时间格式是必须的"); // 只有时间 if (!string.IsNullOrWhiteSpace(dateTimeFormat) && string.IsNullOrWhiteSpace(timezoneFormat)) { var datetimeStr = DateTimeHelper.FormatDateTime(dateTime, dateTimeFormat); return (true, $"格式化样例:{datetimeStr}"); } // 时间和时区同时存在 if (!string.IsNullOrWhiteSpace(dateTimeFormat) && !string.IsNullOrWhiteSpace(timezoneFormat)) { var zoneStr = DateTimeHelper.TimezoneFormat(defaultTimeZone, timezoneFormat); var datetimeStr = DateTimeHelper.FormatDateTime(dateTime, dateTimeFormat); dateStr = $"{datetimeStr} {zoneStr}"; return (true, $"格式化样例:{dateStr}"); } } } catch (Exception e) { return (false, $"时间格式错误请检查:{e.Message}"); } // 默认情况 dateTimeFormat ??= "yyyy-MM-ddTHH:mm:ss.fffK"; dateStr = dateTime.ToString(dateTimeFormat); return (true, $"格式化样例:{dateStr}"); } }