track/src/TrackCenter.Application/Services/TrackPush/TrackPushService.cs
2026-02-26 15:45:00 +08:00

351 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Linq.Expressions;
using Fake.Application.Dtos;
using InterfaceForward.Domain.Shared.Helpers;
using TrackCenter.Application.Dtos.TrackPush;
using TrackCenter.Application.Helpers;
using TrackCenter.Application.Services.Warning.Handlers;
using TrackCenter.Domain.Aggregates.OrderAggregate;
using TrackCenter.Domain.Aggregates.TrackPushAggregate;
using TrackCenter.Domain.Dtos.TrackPush;
namespace TrackCenter.Application.Services.TrackPush;
/// <summary>
/// 轨迹推送
/// </summary>
[ApiExplorerSettings(GroupName = "轨迹推送")]
[Route("/Track/PushConfig")]
public class TrackPushService(
ITrackPushConfigRepository trackPushConfigRepository,
TrackPushCacheService trackPushCacheService,
IServiceProvider serviceProvider)
: ApplicationServiceBase, ISingletonDependency
{
/// <summary>
/// 轨迹推送配置列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetPage")]
public async Task<PagedResult<GetTrackPushConfigPageOutputVO>> GetPageAsync([FromBody] KeywordsInputVO input)
{
return await trackPushConfigRepository.GetPageAsync(input);
}
/// <summary>
/// 轨迹推送配置内容列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetContentPage")]
public async Task<PagedResult<GetTrackPushContentPageOutputVO>> GetContentPageAsync(
[FromBody] GetTrackPushContentPageInputVO input)
{
return await trackPushConfigRepository.GetContentPageAsync(input);
}
/// <summary>
/// 轨迹推送配置详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("GetDetail")]
public async Task<GetTrackPushConfigDetailOutputVO> GetDetailAsync(int id)
{
return await trackPushConfigRepository.GetDetailAsync(id);
}
/// <summary>
/// 轨迹推送配置内容详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("GetContentDetail")]
public async Task<GetTrackPushContentDetailOutputVO> GetContentDetailAsync(int id)
{
return await trackPushConfigRepository.GetContentDetailAsync(id);
}
/// <summary>
/// 轨迹推送配置编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("Edit")]
public async Task<string> EditAsync([FromBody] EditTrackPushConfigInput input)
{
if (input.Options != OptionTypeNoNull.删除)
{
Expression<Func<TrackPushConfigEntity, bool>> isAnyExp = x => x.Customer == input.Customer;
if (input.Options == OptionTypeNoNull.修改) isAnyExp = isAnyExp.And(x => x.Id != input.Id);
if (await trackPushConfigRepository.IsAnyAsync(isAnyExp))
throw new BusinessException(message: "配置已存在");
}
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 = TransacationHelper.GetReadCommitted();
switch (input.Options)
{
case OptionTypeNoNull.新增:
var trackPushEntity = ObjectMapper.Map<EditTrackPushConfigInput, TrackPushConfigEntity>(input);
await trackPushConfigRepository.InsertReturnIdentityAsync(trackPushEntity);
await trackPushCacheService.SetPushContentConfigsAsync(trackPushEntity.AppKey,
trackPushEntity.Customer);
break;
case OptionTypeNoNull.修改:
var oldTrackPushEntity = await trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
throw new BusinessException(message: "找不到数据");
ObjectMapper.Map(input, oldTrackPushEntity);
await trackPushConfigRepository.UpdateAsync(oldTrackPushEntity);
await trackPushCacheService.SetPushContentConfigsAsync(oldTrackPushEntity.AppKey,
oldTrackPushEntity.Customer);
break;
case OptionTypeNoNull.删除:
var entity = await trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ??
throw new BusinessException(message: "找不到数据");
await trackPushConfigRepository.SoftDeleteAsync(x => x.Id == input.Id);
await trackPushConfigRepository.SoftDeleteContentAsync(x => x.TrackPushConfigId == input.Id);
await trackPushCacheService.SetPushContentConfigsAsync(entity.AppKey, entity.Customer);
break;
default:
throw new ArgumentOutOfRangeException();
}
ts.Complete();
return msg;
}
/// <summary>
/// 轨迹推送配置内容编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditContent")]
public async Task<bool> EditContentAsync([FromBody] EditTrackPushContentInput input)
{
if (input.Options != OptionTypeNoNull.删除)
{
Expression<Func<TrackPushContentConfigEntity, bool>> 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: "TrackContentId配置已存在");
if (!input.TrackContentCodeValue.IsNullOrWhiteSpace() &&
await trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x =>
x.TrackContentCodeValue == input.TrackContentCodeValue)))
throw new BusinessException(message: "TrackContentCodeValue配置已存在");
if (!input.TrackStatusValue.IsNullOrWhiteSpace() &&
await trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x =>
x.TrackStatusValue == input.TrackStatusValue)))
throw new BusinessException(message: "TrackStatusValue配置已存在");
if (!input.TrackContentValue.IsNullOrWhiteSpace() &&
await trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x =>
x.TrackContentValue == input.TrackContentValue)))
throw new BusinessException(message: "TrackContentValue配置已存在");
if (!input.TrackEnContentValue.IsNullOrWhiteSpace() &&
await trackPushConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x =>
x.TrackEnContentValue == input.TrackEnContentValue)))
throw new BusinessException(message: "TrackEnContentValue配置已存在");
}
var trackPushConfigId = input.TrackPushConfigId;
using var ts = TransacationHelper.GetReadCommitted();
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<EditTrackPushContentInput, TrackPushContentConfigEntity>(input);
entity.Sort = maxSort + 1;
await trackPushConfigRepository.InsertContentAsync(entity);
break;
}
case OptionTypeNoNull.修改:
{
var entity = await trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: "找不到数据");
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: "找不到数据");
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 ArgumentOutOfRangeException();
}
var pushConfig = await trackPushConfigRepository.GetFirstAsync(x => x.Id == trackPushConfigId);
if (pushConfig != null)
{
await trackPushCacheService.SetPushContentConfigsAsync(pushConfig.AppKey, pushConfig.Customer);
}
ts.Complete();
// 引发预警计算
WarningCalc_PushContentConfigChanged(pushConfig, oldContentConfig, postContentConfig);
return true;
}
/// <summary>
/// 轨迹推送配置内容排序
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("SortContent")]
public async Task<bool> 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 = TransacationHelper.GetReadCommitted();
await trackPushConfigRepository.UpdateContentRangeAsync(trackPushContentEntities);
var pushConfig = await trackPushConfigRepository.GetFirstAsync(
x => x.Id == trackPushContentEntities[0].TrackPushConfigId,
y => new
{
y.AppKey,
y.Customer
});
if (pushConfig != null)
{
await trackPushCacheService.SetPushContentConfigsAsync(pushConfig.AppKey, pushConfig.Customer);
}
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<IReturnWarningHandler>();
await handler.PushConfigChangedHandleAsync(pushConfig, contentConfigEntity);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
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}");
}
}